913. Cat and Mouse

A game on an undirected graph is played by two players, Mouse and Cat, who alternate turns.

The graph is given as follows: graph[a] is a list of all nodes b such that ab is an edge of the graph.

Mouse starts at node 1 and goes first, Cat starts at node 2 and goes second, and there is a Hole at node 0.

During each player's turn, they must travel along one edge of the graph that meets where they are. For example, if the Mouse is at node 1, it must travel to any node in graph[1].

Additionally, it is not allowed for the Cat to travel to the Hole (node 0.)

Then, the game can end in 3 ways:

  • If ever the Cat occupies the same node as the Mouse, the Cat wins.
  • If ever the Mouse reaches the Hole, the Mouse wins.
  • If ever a position is repeated (ie. the players are in the same position as a previous turn, and it is the same player's turn to move), the game is a draw.

Given a graph, and assuming both players play optimally, return 1 if the game is won by Mouse, 2 if the game is won by Cat, and 0 if the game is a draw.

Example 1:

Input: [[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
Output: 0
Explanation:
4---3---1
|   |
2---5
 \ /
  0

Note:

  1. 3 <= graph.length <= 50
  2. It is guaranteed that graph[1] is non-empty.
  3. It is guaranteed that graph[2] contains a non-zero element.
class Solution:
    def catMouseGame(self, graph):
        """
        :type graph: List[List[int]]
        :rtype: int
        """
        n = len(graph)
        color = [[[0]*3 for i in range(n)] for j in range(n)]
        #color中分别代表mouse的位置,cat的位置,mouse或cat的turn,1代表mouse,2代表cat
        q = []
        for i in range(1,n): #初始状态标记
            for t in range(1,3):
                color[0][i][t] = 1 #对于这种状态,肯定是mouse win
                q.append((0,i,t))
                color[i][i][t] = 2 #对于这种状态,肯定是cat win
                q.append((i,i,t))
        while len(q):
            curstatus = q.pop(0)
            mouse,cat,turn = curstatus
            for prestatus in self.findallprestatus(graph,curstatus):
                premouse,precat,preturn = prestatus
                if color[premouse][precat][preturn] !=0: #已经被标记
                    continue
                if color[mouse][cat][turn]==3-turn:
                #从队列中取出队首节点状态(m,c,t),找到它的所有邻接的parent的状态(m2,c2,t2).
                #这里的父子关系是指,(m2,c2,t2)通过t2轮(老鼠或猫)的操作,能得到(m,c,t).
                #我们发现,如果(m,c,t)是老鼠赢而且t2是老鼠轮,那么这个(m2,c2,t2)一定也是老鼠赢.同理,猫赢的状态也类似.
                    color[premouse][precat][preturn] = preturn
                    q.append(prestatus)
                elif self.allneighbourswin(color,graph,prestatus):
                #对于(m2, c2, t2),我们再去查询它的所有children(必定是对手轮)是否都已经标注了赢的状态.如果都是赢的状态,那么说明(m2, c2, t2)
                #无路可走,只能标记为输的状态.特别注意的是,第一条规则通过child找parent,和第二条规则通过parent找child的算法细节是不一样的,一定要小心.
                    color[premouse][precat][preturn] = 3-preturn
                    q.append(prestatus)
        return color[1][2][1]

    def findallprestatus(self,graph,curstatus):
        res = []
        mouse,cat,turn = curstatus
        if turn==1: #前一步该cat走
            for precat in graph[cat]:#只可能来自与其相邻的点
                if precat==0:#猫不可以进洞
                    continue
                res.append((mouse,precat,2))
        else: #前一步该mouse走
            for premouse in graph[mouse]:
                res.append((premouse,cat,1))
        return res

    def allneighbourswin(self,color,graph,status):#查询所有的子节点是否已无路可走
        mouse,cat,turn = status
        if turn==1:
            for nextmouse in graph[mouse]:
                if color[nextmouse][cat][2] != 2:
                    return False
        elif turn==2:
            for nextcat in graph[cat]:
                if nextcat==0:
                    continue
                if color[mouse][nextcat][1]!=1:
                    return False
        return True

参考:https://blog.csdn.net/fuxuemingzhu/article/details/83350880

猜你喜欢

转载自www.cnblogs.com/bernieloveslife/p/10238936.html
cat