解法
一开始想用alpha-beta啥的,但是超时了
mouse, cat, player
代表游戏的每一个状态,把游戏运行过程想像成这些状态连成的有向图。
其中有的状态的马上就被判断出结果:
(0,cat,player)
:这种情况一定是老鼠赢,着色为MOUSE
(i,i,player)
:这种情况一定是猫赢,着色为CAT
还有些状态能被间接着色:
(mouse, cat, player)
的后继节点只要有一个着色为player
时,它就能被着色为player
。(mouse, cat, player)
的后继节点全都被着色为另一个player
时,它就会被着色为另一个player
。
所有的节点都着色完之后(不管是直接还是间接),剩下的节点都是平局节点。最后我们只关心(1,2,MOUSE)
的着色是什么。
算法这样进行:
- 先统计每个状态的子节点的数量,记作
d[m,c,p]
,我们用它来代表未被着色为对家的子节点数量。 - 然后对所有能直接着色的节点着色,把它们放到队列里。
- 对于队列里的每个已着色为color的节点,找到它们的每个父节点
m1,c1,p1
,如果它还没着色:- 如果
color==p1
,那么父节点可以直接被着色为color
,然后我们把这个节点加入队列。 - 否则,我们把未被着色为对家的子节点数量减一:
d[m1,c1,p1]-=1
,如果减完之后未遍历节点为0了,说明这个父节点的所有子节点都被着色为了另一个player,那么它当然也只能被着色为另一个player,我们着色并将此节点添加到队列。
- 如果
- 最后输出
1,2,MOUSE
的状态即可
特别注意猫不能走0的设定!!!!
class Solution(object):
def catMouseGame(self, graph):
"""
:type graph: List[List[int]]
:rtype: int
"""
from collections import defaultdict
DRAW, MOUSE, CAT = 0,1,2
color = defaultdict(int)
queue = []
n = len(graph)
for i in xrange(n):
for player in xrange(1,3):
color[(0, i, player)] = MOUSE
queue.append((0, i, player, MOUSE))
if i>0:
color[(i, i, player)] = CAT
queue.append((i,i,player,CAT))
d = {}
for m,c in itertools.product(xrange(n), repeat=2):
d[(m,c,MOUSE)] = len(graph[m])
d[(m,c,CAT)] = len(graph[c])-(0 in graph[c])
def parents(m,c,p):
if p==MOUSE:
for c0 in graph[c]:
if c0:
yield m,c0,3-p
else:
for m0 in graph[m]:
yield m0,c,3-p
while len(queue):
mouse,cat ,player, col = queue.pop(0)
for m,c,p in parents(mouse, cat, player):
if color[(m,c,p)]==DRAW:
if p==col:
color[(m,c,p)] = col
queue.append((m,c,p,col))
else:
d[(m,c,p)] -= 1
if d[(m,c,p)] == 0:
color[(m,c,p)] = 3-p
queue.append((m,c,p,3-p))
return color[(1,2,1)]