Leetcode 913. 猫和老鼠 【dp】【dfs剪枝】

两个玩家分别扮演猫(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] 包含非零元素。

 

设图中节点数为n

dp数组dp[c][m][d]c为cat的位置,m是mouse的位置,d是当前已经走的步数

判断是够会平局就是判断是否会出现重复的路线,当每个人都走n步,共计2n步时一定会出现重复路线,即可返回0(平局)

当c==m的时候老鼠和猫在同一位置,返回2,猫胜,当m==0时老鼠回到洞里,返回1,老鼠胜

但要注意c不能等于0

dfs实现中通过当前d的奇偶判断到谁的回合,在猫的回合中假设猫会选择最优解,所以所有下一可行节点中只要有一个是可以返回2的,就直接返回dp[c][m][d]=2,若没有一定获胜的可能性,也不能直接判断当前dp[c][m][d]是等于0还是等于1,因为猫会选择最优解,所以除非所有可行节点全部返回1(老鼠胜),否则一定会反会0

老鼠的回合同理

具体实现看代码

class Solution {
public:
    int catMouseGame(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, vector<int>(n * 2, -1)));
        return dfs(2, 1, 0, graph, dp);
    }
    int dfs(int c, int m, int d, vector<vector<int>>& v, vector<vector<vector<int>>>& dp) {
        if(d == 2 * v.size()) return 0;
        if(c == m) return dp[c][m][d] = 2;
        if(m == 0) return dp[c][m][d] = 1;
        if(dp[c][m][d] != -1) return dp[c][m][d];
        if(d & 1) {
            bool mw = 1;
            for(int i = 0; i < v[c].size(); i++) {
                if(v[c][i] == 0) continue;
                int next = dfs(v[c][i], m, d + 1, v, dp);
                if(next == 2) return dp[c][m][d] = 2;
                else if(next != 1) mw = 0;
            }
            if(mw) return dp[c][m][d] = 1;
            else return dp[c][m][d] = 0;
        } else {
            bool cw = 1;
            for(int i = 0; i < v[m].size(); i++) {
                int next = dfs(c, v[m][i], d + 1, v, dp);
                if(next == 1) return dp[c][m][d] = 1;
                else if(next != 2) cw = 0;
            }
            if(cw) return dp[c][m][d] = 2;
            else return dp[c][m][d] = 0;
        }
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值