[leetcode 913] 猫和老鼠(博弈、dp)

题目链接:

https://leetcode-cn.com/problems/cat-and-mouse/

题目大意:

在这里插入图片描述
在一张无向图中,老鼠开始处于1号点,猫开始处于2号点,0号点是洞(猫不能进入),猫鼠交替移动(老鼠先)。
若老鼠能进入洞中,即老鼠胜,输出1;若猫能抓住老鼠(猫鼠同在一共点),即猫胜,输出2;否则则为平局,输出0。

解题思路:

这题可以用状态转移,将初始状态转移到已知的胜负的状态中。

我们可以使用一个三维数组 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示当老鼠在 i i i 位置,猫在 j j j 位置,游戏进行了 k k k 轮时的胜负关系。

那么,我们可以先把确定的胜负关系罗列一下:

1.当老鼠位于0号点位时,老鼠必胜,即 d p [ 0 ] [ j ] [ k ] = 1 dp[0][j][k]=1 dp[0][j][k]=1
2.当猫鼠位于相同位置时,猫必胜,即 d p [ x ] [ x ] [ k ] = 2 dp[x][x][k]=2 dp[x][x][k]=2
3.当游戏进行2*n轮之后,即可认定为是平局的情况,即 d p [ i ] [ j ] [ 2 ∗ n ] = 0 dp[i][j][2*n]=0 dp[i][j][2n]=0
(猫鼠都进行了n轮游戏,若仍未能分出胜负,则代表至少存在1个点老鼠已经到达两次,则说明无论对于猫鼠,都已经不再存在必胜点了)

而对于状态转移,可以遵循几个关系:

1.若下一步存在能够必胜的状态,则可以直接转移过去,即可直接确定必胜关系,结束遍历
2.若下一步只存在必败状态,则可直接确定必败关系,结束遍历
3.若下一步存在仍不确定(或必和)的状态,可先移动至此,再继续寻找后续必胜状态

因为移动的先后关系,我们可以将奇数回合当为老鼠移动,而偶数回合即为猫移动
对此,只需再注意一个点,即猫不能去到0号点即可

上代码:

class Solution {
public:
    int n,dp[55][55][105];
    vector< vector<int> > p;
    int catMouseGame(vector<vector<int>>& graph) {
        n=graph.size();
        p=graph;
        memset(dp,-1,sizeof(dp));
        return GetResult(1,2,0);
    }
    int GetResult(int x,int y,int turn)
    {
        if(turn>=2*n)   //回合数大于2*n,返回和状态
            return 0;
        if(dp[x][y][turn]==-1)
        {
            if(x==0) dp[x][y][turn]=1;  //老鼠入洞,老鼠胜
            else if(x==y) dp[x][y][turn]=2;   //猫抓到老鼠,猫胜
            else dp[x][y][turn]=GetNext(x,y,turn);  //若不能确定,则继续找
        }
        return dp[x][y][turn];
    }
    int GetNext(int x,int y,int turn)
    {
        int move=turn%2==0?x:y;   //确定当前回合移动的对象(猫、鼠)
        int defaultResult=move==x?2:1;   
        int result=defaultResult;  //将初始胜负状态确定为必败
        for(int i:p[move])
        {
            if(move==y&&i==0)  //猫不能到达0号点
                continue;
            int nx=move==x?i:x;
            int ny=move==y?i:y;
            int next=GetResult(nx,ny,turn+1);  //找下一个点的胜负关系
            if(next!=defaultResult)
            {
                result=next;
                if(next!=0)   //若这个点不是和的状态(即必胜必败已定),即可退出遍历
                    break;
            }
        }
        return result;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值