Python 获取图形中唯一状态的数量

Python 获取图形中唯一状态的数量,python,recursion,graph-theory,discrete-mathematics,induction,Python,Recursion,Graph Theory,Discrete Mathematics,Induction,我一直在尝试解决麻省理工学院的计算机科学数学习题集,这里有一个问题: 每个进入永乐寺的僧侣都会得到一个碗,里面有15颗红色的珠子和12颗绿色的珠子。每当时间之锣响起时,僧侣必须做两件事中的一件: 交换:如果他碗里有3颗红色的珠子,那么他可以用3颗红色的珠子交换2颗绿色的珠子 交换:他可以用红珠子替换碗中的每个绿珠子,用绿珠子替换碗中的每个红珠子。也就是说,如果他从i红色珠子和j绿色珠子开始,那么在他执行此操作后,他将有j红色珠子和i绿色珠子 一个和尚只有在碗里正好有5颗红珠和5颗绿珠的情况下才能

我一直在尝试解决麻省理工学院的计算机科学数学习题集,这里有一个问题:

每个进入永乐寺的僧侣都会得到一个碗,里面有15颗红色的珠子和12颗绿色的珠子。每当时间之锣响起时,僧侣必须做两件事中的一件:

  • 交换:如果他碗里有3颗红色的珠子,那么他可以用3颗红色的珠子交换2颗绿色的珠子
  • 交换:他可以用红珠子替换碗中的每个绿珠子,用绿珠子替换碗中的每个红珠子。也就是说,如果他从i红色珠子和j绿色珠子开始,那么在他执行此操作后,他将有j红色珠子和i绿色珠子
  • 一个和尚只有在碗里正好有5颗红珠和5颗绿珠的情况下才能离开永世寺

    这其中有一些子问题:

  • 证明没有人离开过圣殿。我用数学归纳法证明了这一点
  • 证明这个问题只能达到有限个状态。这一证明也是通过数学归纳法完成的,证明了红色珠子和绿色珠子的数量之和只能减少或保持不变
  • (这就是我被卡住的地方)一个僧侣在任何执行永世殿机器的过程中可以访问的唯一状态的真实最大数量是多少
  • 在花了相当长的时间思考子问题3之后,我放弃了,决定写一个程序来计算唯一状态的数量

    class Node:
        def __init__(self, r, g):
            self.r = r
            self.g = g
    
        def swap(self):
            if self.g <= 0 or self.r <= 0:
                return None
            return Node(self.g, self.r)
    
        def exchange(self):
            if self.r >= 3:
                return Node(self.r - 3, self.g + 2)
            return None
    
        def __hash__(self):
            return hash((self.r, self.g))
    
        def __eq__(self, other):
            if self is None and other is None:
                return True
            if self is None or other is None:
                return False
            return self.r == other.r and self.g == other.g
    
        def __repr__(self):
            return "({}, {})".format(self.r, self.g)
    
    start = Node(15, 12)
    queue = []
    graph = []
    visited = set()
    queue.append(start)
    
    while (queue):
        curr = queue.pop(0)
        visited.add(curr)
        graph.append(curr)
        s = curr.swap()
        e = curr.exchange()
    
        for el in [s, e]:
            if el != None:
                if el not in visited:
                    queue.append(el)
    
    print(visited, len(visited))
    
    类节点:
    定义初始化(self,r,g):
    self.r=r
    self.g=g
    def交换(自):
    if self.gEdit:根据OP自己的回答和我们在评论中的讨论,这是关键问题:

    我们必须区分两个不同的数字:

  • 僧侣可以走的任何一条路径中访问状态的最大数量n
  • 僧侣能到达的州的总数
  • 注意,N是在任何一条路径中访问的状态集的并集(接管所有可能路径)的基数。这意味着n2: 如果x<3: x、 y=交换(x,y) 其他: coinflip=random.randint(0,1) 如果coinflip==0: x、 y=交换(x,y) 其他: x、 y=交换(x,y) visted=visted.union({(x,y)}) x、 y=交换(x,y) visted=visted.union({(x,y)}) 打印('已访问状态:',已访问) 打印('访问的州数:',len(已访问))
    被访问国:{(18,0)、(4,7)、(1,3)、(3,0)、(0,2)、(4,12)、(11,14)、(2,5)、(0,3)、(8,5)、(5,8)、(15,12)、(8,1)、(16,3)、(5,18)、(1,14)、(14,1)、(3,16)、(8,16)、(4,1)、(12,14)、(2,20)、(0,18)、(2,10)、(1,4)、(1,19)、(4,2)、(17,4)、(5,3)、(14,11)、(4,6)、(15,2)、(20,2)、(16,8)、(4,17)、(3)、(4)、(1),(14,12),(1,8),(12,4),(2,0),(19,1),(5,2),(2,4),(10,2)}

    访问的国家数目:46

    更新:这里是完整状态空间的绘图N=140


    这是一条访问52个州的路线。绿色的X是起点,每个蓝色的圆圈表示一个访问状态。因为我们从引用的证据中知道,n问题中的代码所构建的图连接了每个可能的状态,因此计算了状态机可能的状态总数,但不计算僧侣在执行“永恒之殿”机器时可以访问的唯一状态的最大数

    通过以类似BFS的方式计算节点,我假设可以通过任何其他状态到达每个状态。事实并非如此。交换操作创建新状态后,不可能通过交换(显然)返回到其“父”状态,因此一旦在锣圈做出选择,就不会有任何返回

    因此,我们真正需要做的是构建图,从起始节点开始执行DFS,并跟踪在DFS遍历期间实现的最大深度。这个最大深度就是我们想要的解决方案

    代码如下:

    class Node:
        def __init__(self, r, g):
            self.r = r
            self.g = g
    
        def swap(self):
            ## if self.g <= 0 or self.r <= 0:
                ## return None
            ## Swaps with 0 allowed (only by commenting
            ## out the code above I get 52)
            return Node(self.g, self.r)
    
        def exchange(self):
            if self.r >= 3:
                return Node(self.r - 3, self.g + 2)
            return None
    
        def neighbours(self):
            s = self.swap()
            e = self.exchange()
            n = []
            for el in [s, e]:
                if el is not None:
                    n.append(el)
            return n
    
        def __hash__(self):
            return hash((self.r, self.g))
    
        def __eq__(self, other):
            if self is None and other is None:
                return True
            if self is None or other is None:
                return False
            return self.r == other.r and self.g == other.g
    
        def __repr__(self):
            return "({}, {})".format(self.r, self.g)
    
    start = Node(15, 12)
    dfs_visited = set()
    max_len = [0]  ## need a mutable data structure
    
    def dfs(s, curr_len):
        for n in s.neighbours():
            if curr_len > max_len[0]:
                max_len[0] = curr_len
            if n not in dfs_visited:
                dfs_visited.add(n)
                dfs(n, curr_len+1)
        return max_len[0]
    
    print(dfs(start, 0))
    
    类节点:
    定义初始化(self,r,g):
    self.r=r
    self.g=g
    def交换(自):
    ##如果self.g max_len[0]:
    最大长度[0]=当前长度
    如果n不在dfs中,请访问:
    dfs_已访问。添加(n)
    dfs(n,当前长度+1)
    返回最大长度[0]
    打印(dfs(开始,0))
    
    五十二


    我不确定是在这里还是在交换。如果需要,我可以在这里删除它,然后发布到那里。“因此,我们可以通过交换操作获得25个新的州。”不,解决方案没有这样说。注意区分访问状态的顺序和唯一状态集。你是对的。解决方案声明“序列中最多可以有25个交换操作”,但在最后,他们还声明“机器执行中唯一状态数的上限为25+25+1=52”,除非我也误解了这一点,这句话不是告诉我们,唯一状态集合中的元素数量最多是52个吗?但是我的程序,像BFS一样执行状态机,会给我一组129个唯一的状态?是的,我知道给定的解决方案和程序的结果之间存在矛盾。我想说的是引用的证据看起来很有说服力,但我不知道你的代码哪里出错了。也许一些视觉直觉可以帮助你:把状态想象成x-y网格中的点。x是红色珠子的数量,y是绿色珠子的数量。然后,唯一可能的状态更改是“对角镜像”(交换)或“向左3,向上2”(交换)。记住这一点,遵循你引用的证据可能会更容易。阿恩!非常感谢你。你的回答,虽然你说“不是一个完整的答案”让我立刻意识到我在哪里