877石子游戏;913猫和老鼠

亚历克斯和李用几堆石子在做游戏。偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] 。

游戏以谁手中的石子最多来决出胜负。石子的总数是奇数,所以没有平局。

亚历克斯和李轮流进行,亚历克斯先开始。 每回合,玩家从行的开始或结束处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中石子最多的玩家获胜。

假设亚历克斯和李都发挥出最佳水平,当亚历克斯赢得比赛时返回 true ,当李赢得比赛时返回 false 。

 

示例:

输入:[5,3,4,5]
输出:true
解释:
亚历克斯先开始,只能拿前 5 颗或后 5 颗石子 。
假设他取了前 5 颗,这一行就变成了 [3,4,5] 。
如果李拿走前 3 颗,那么剩下的是 [4,5],亚历克斯拿走后 5 颗赢得 10 分。
如果李拿走后 5 颗,那么剩下的是 [3,4],亚历克斯拿走后 4 颗赢得 9 分。
这表明,取前 5 颗石子对亚历克斯来说是一个胜利的举动,所以我们返回 true 。


 

提示:


    2 <= piles.length <= 500
    piles.length 是偶数。
    1 <= piles[i] <= 500
    sum(piles) 是奇数。

class Solution {//dp[i][j]表示i~j先手能获得最大值 sum[j+1]-sum[i]表示i~j的求和
public:
    bool stoneGame(vector<int>& piles) {
        int pSize=piles.size();
        vector<vector<int>>dp(pSize,vector<int>(pSize,0));
        vector<int>sum(pSize+1,0);
        for(int i=1;i<=pSize;++i)
            sum[i]=sum[i-1]+piles[i-1];
        for(int i=0;i<pSize;++i)
            dp[i][i]=piles[i];            
        for(int j=1,sumij;j<pSize;++j)//内外层循环遍历初始值和结束值不会写
            for(int i=j-1;i>=0;--i){//草稿图画出二维矩阵,找到初始已知数据(对角线)和转移推导顺序(先那一行/列,再哪一列/行),最后确定最终结果是矩阵的哪个数据(一般四个角)或那一行/列数据的最值
                sumij=sum[j+1]-sum[i];
                dp[i][j]=max(sumij-dp[i+1][j],sumij-dp[i][j-1]);//转移方程
            }
        return dp[0][pSize-1]>sum[pSize]-dp[0][pSize-1];
    }
};


//内外层循环遍历初始值和结束值


/*确定最终答案是dp[0][size-1]还是dp[size-1][0]还是dp[size-1][size-1]还是全部dp[i][j]中的某个最值。
确定每个数组元素是根据那些数组元素计算得到。从而确定先行还是先列,
确定行从上到下还是从下到上,
确定列从左到右还是从右到左,
只要涉及对对角线临界值则引用上个循环的循环变量*/
//方法一<==>方法三
for(int j=1;j<size;++j){
	for(int i=j-1;i>=0;--i){
		dp[i][j]:第一列到队后一列 依次 从对角线上一行到第一行
//方法二<==>方法四
for(int j=1;j<size;++j){//列
	for(int i=0;i<j;++i){
		dp[i][j]:第一列到队后一列 依次 从第一行到对角线上一行
//方法三
for(int i=size-2;i>=0;--i)
	for(int j=i+1;j<size;++j)
		dp[i][j]:对角线最后上一行到第一行 依次 从对角线右一列到最后一列
//方法四
for(int i=size-2;i>=0;--i)
	for(int j=size-1;j>=i+1;--j)
		dp[i][j]:对角线最后上一行到第一行 依次 从最后一列到对角线右一列
class Solution {//根据画出的二维草稿图可以知道,二维dp可以优化成一维dp
public:
    bool stoneGame(vector<int>& piles) {
        int pSize=piles.size();
        vector<int>dp(pSize,0);
        vector<int>sum(pSize+1,0);
        for(int i=1;i<=pSize;++i)
            sum[i]=sum[i-1]+piles[i-1];
        for(int i=0;i<pSize;++i)
            dp[i]=piles[i];            
        for(int j=1,sumij;j<pSize;++j){
            for(int i=j-1;i>=0;--i){
                sumij=sum[j+1]-sum[i];
                dp[j]=max(sumij-dp[j],sumij-dp[j-1]);
            }
        }
        return dp[pSize-1]>sum[pSize]-dp[pSize-1];
    }
};

两个玩家分别扮演猫(Cat)和老鼠(Mouse)在无向图上进行游戏,他们轮流行动。

该图按下述规则给出:graph[a] 是所有结点 b 的列表,使得 ab 是图的一条边。

老鼠从结点 1 开始并率先出发,猫从结点 2 开始且随后出发,在结点 0 处有一个洞。

在每个玩家的回合中,他们必须沿着与他们所在位置相吻合的图的一条边移动。例如,如果老鼠位于结点 1,那么它只能移动到 graph[1] 中的(任何)结点去。

此外,猫无法移动到洞(结点 0)里。

然后,游戏在出现以下三种情形之一时结束:


    如果猫和老鼠占据相同的结点,猫获胜。
    如果老鼠躲入洞里,老鼠获胜。
    如果某一位置重复出现(即,玩家们的位置和移动顺序都与上一个回合相同),游戏平局。


给定 graph,并假设两个玩家都以最佳状态参与游戏,如果老鼠获胜,则返回 1;如果猫获胜,则返回 2;如果平局,则返回 0。

 

 


示例:

输入:[[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
输出:0
解释:
4---3---1
|   |
2---5
 \ /
  0


 

提示:


    3 <= graph.length <= 200
    保证 graph[1] 非空。
    保证 graph[2] 包含非零元素。

class Solution {//平局的判定有误,错误答案
    vector<vector<int>> graph;
    vector<vector<vector<int>>>  visited,state;
    enum result{
        Draw,Mousewin,Catwin
    };
    enum turn{
        Cat,Mouse
    };
public:
    int catMouseGame(vector<vector<int>>& graph) {
        this->graph=graph;
        visited.resize(200,vector<vector<int>>(200,vector<int>(2,0)));
        state.resize(200,vector<vector<int>>(200,vector<int>(2,-1)));
        return helper(1,2,1);
    }
    int helper(int m,int c,int player){//plyaer:1表示老鼠m,0表示猫c;
        if(m==c)return Catwin;
        else if(m==0)return Mousewin;
        else if(visited[m][c][player])return Draw;
        else if(state[m][c][player]!=-1)return state[m][c][player];
        if(player==Mouse){
            visited[m][c][player]=1;
            int len=graph[m].size();
            bool draw=false;
            for(int i=0;i<len;++i){
                //if(visited[graph[m][i]][c][Cat])continue;
                int res=helper(graph[m][i],c,Cat);
                if(res==Mousewin){
                    visited[m][c][player]=0;
                    return state[m][c][player]=Mousewin;
                }
                else if(res==Draw)
                    draw=true;
            }
            visited[m][c][player]=0;
            return state[m][c][player]=draw?Draw:Catwin;
        }
        else{
            visited[m][c][player]=1;
            int len=graph[c].size();
            bool draw=false;
            for(int i=0;i<len;++i){
                if(graph[c][i]==0)continue;//
                int res=helper(m,graph[c][i],Mouse);
                if(res==Catwin){
                    visited[m][c][player]=0;
                    return state[m][c][player]=Catwin;
                }
                else if(res==Draw)
                    draw=true;
            }
            visited[m][c][player]=0;
            return state[m][c][player]=draw?Draw:Mousewin;
        }
    }
};
//状态改为(m,c,step),step表示走了多少步数
//步数大于2*graph.size()则判断平局,原理未知
class Solution {
    vector<vector<int>> graph;
    vector<vector<vector<int>>>state;
    enum result{
        Draw,Mousewin,Catwin
    };
    enum turn{
        Cat,Mouse
    };
public:
    int catMouseGame(vector<vector<int>>& graph) {
        this->graph=graph;
        state.resize(200,vector<vector<int>>(200,vector<int>(400,-1)));
        return helper(1,2,1);
    }
    int helper(int m,int c,int step){//plyaer:1表示老鼠m,0表示猫c;
        if(m==c)return Catwin;
        if(m==0)return Mousewin;
        if(step>graph.size())return Draw;
        if(state[m][c][step]!=-1)return state[m][c][step];
        if((step&1)==Mouse){
            int len=graph[m].size();
            bool draw=false;
            for(int i=0;i<len;++i){
                int res=helper(graph[m][i],c,step+1);
                if(res==Mousewin){
                    return state[m][c][step]=Mousewin;
                }
                else if(res==Draw)
                    draw=true;
            }
            return state[m][c][step]=draw?Draw:Catwin;
        }
        else{
            int len=graph[c].size();
            bool draw=false;
            for(int i=0;i<len;++i){
                if(graph[c][i]==0)continue;//
                int res=helper(m,graph[c][i],step+1);
                if(res==Catwin){
                    return state[m][c][step]=Catwin;
                }
                else if(res==Draw)
                    draw=true;
            }
            return state[m][c][step]=draw?Draw:Mousewin;
        }
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值