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

2024-06-16 12:47:56 发布

您现在位置:Python中文网/ 问答频道 /正文

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

Each monk entering the Temple of Forever is given a bowl with 15 red beads and 12 green beads. Each time the Gong of Time rings, a monk must do one of two things:

  1. Exchange: If he has 3 red beads in his bowl, then he may exchange 3 red beads for 2 green beads.
  2. Swap: He may replace each green bead in his bowl with a red bead and replace each red bead in his bowl with a green bead. That is, if he starts with i red beads and j green beads, then after he performs this operation, he will have j red beads and i green beads.

A monk may leave the Temple of Forever only when he has exactly 5 red beads and 5 green beads in his bowl.

这其中有一些子问题:

  1. 证明没有人离开过圣殿。我用数学归纳法证明了这一点
  2. 证明这个问题只能达到有限个状态。这一证明也是通过数学归纳法完成的,证明了红色珠子和绿色珠子的数量之和只能减少或保持不变
  3. (这就是我被卡住的地方)一个僧侣在任何执行永世殿机器的过程中可以访问的唯一状态的真实最大数量是多少

在花了相当长的时间思考子问题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))

我从程序中得到的答案是

{(6, 9), (16, 9), (0, 7), (2, 5), (8, 5), (5, 8), (10, 8), (10, 7), (16, 3), (5, 18), (0, 17), (14, 1), (8, 15), (10, 13), (4, 16), (9, 16), (7, 5), (14, 2), (13, 10), (3, 1), (6, 13), (20, 3), (3, 11), (4, 12), (10, 3), (6, 14), (7, 15), (18, 5), (3, 6), (8, 6), (4, 1), (9, 7), (6, 4), (11, 4), (16, 4), (5, 17), (11, 9), (0, 18), (14, 6), (13, 6), (19, 2), (18, 6), (1, 19), (15, 7), (0, 8), (4, 11), (3, 5), (4, 6), (9, 2), (5, 7), (4, 17), (11, 3), (7, 4), (14, 12), (12, 4), (19, 1), (3, 15), (1, 3), (5, 13), (3, 21), (11, 14), (12, 9), (18, 1), (15, 12), (2, 19), (3, 10), (1, 14), (8, 10), (9, 11), (3, 16), (8, 16), (11, 13), (0, 22), (17, 5), (6, 18), (7, 14), (12, 14), (19, 6), (15, 3), (2, 20), (1, 4), (0, 12), (1, 9), (4, 2), (2, 14), (9, 6), (5, 3), (6, 8), (11, 8), (16, 8), (14, 7), (13, 5), (1, 18), (2, 4), (9, 12), (4, 7), (9, 1), (12, 5), (15, 8), (0, 3), (2, 9), (8, 1), (5, 12), (3, 20), (10, 12), (6, 3), (9, 17), (7, 10), (12, 10), (13, 11), (1, 13), (8, 11), (2, 10), (0, 23), (17, 4), (6, 19), (14, 11), (12, 15), (7, 9), (13, 1), (17, 9), (15, 2), (20, 2), (0, 13), (21, 3), (1, 8), (2, 15), (5, 2), (10, 2)} 129

所以,129。但当我看问题集的解决方案时(对于子问题#3),下面是它的说明

Each move in the sequence must be either an exchange or swap, since these are the only legal moves. Now, whenever the monk performs an exchange operation, the sum r + g decreases by one.

(r - 3) + (g + 2) = (r + g) - 1

In contrast, swaps do not have any effect on the sum. Furthermore, we know that the sum r + g must be at least 3 to perform an exchange operation. Therefore, there can be at most 25 exchange operations in the sequence.

Now consider swap operations: between each pair of exchanges in the sequence, there may be an unlimited number of swaps. However, only a single swap can take the monk to a new state: if at step k the monk is in state (r, g), then at step k + 2, he will return to the same state. Therefore, an upper bound on the number of unique states in any execution of the machine is 25 + 26 + 1 = 52 (if swaps are inserted at both the beginning and end of the sequence).

我的程序哪里出错了?我对问题陈述的理解是否不正确(与我编写的程序不符)?而且,我真的不理解他们给出的解决方案。有更好的解释方法吗?例如,我不了解的一个问题/事情是,解决方案指出,每次交换操作,珠子的总和减少1。因此,我们可以通过交换操作获得25个新的州。但图中每一层的每一个和都可以用多种方式表示,是吗?那么必须有更多的状态是通过exchange操作创建的?这是完整问题集的link,它是solution


Tags: andoftheinselfnonereturnif
2条回答

由问题中的代码构建的图形连接了每个可能的状态,因此计算了状态机可能的状态总数,但不计算僧侣在执行“永恒之殿”机器时可以访问的唯一状态的最大数量

通过以类似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))

52

编辑:根据OP自己的回答和我们在评论中的讨论,这是关键问题:

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

  1. 僧侣可以走的任何一条路径中访问状态的最大数量
  2. 僧侣能达到的状态总数

请注意,N是在任何一条路径中访问的状态集的并集(接管所有可能路径)的基数。这意味着n<;=N,很容易看出这些数字是不相等的。麻省理工学院的问题是关于n,而OP的原始代码是为了找到n


引用的证明是正确的,因此“关于[n]的上限是25+26+1=52”

我尝试了一种蒙特卡罗方法来近似N:只要有选择,就随机决定是交换还是交换,重复这个过程,直到这个过程在(2,0)和(0,2)之间振荡,并且重复所有这一切很多次,同时跟踪所有唯一的访问状态

然而,这似乎并不实际,因为可能路径的数量太多,因此我们得到的数量在任何可行的迭代次数下都不接近N。以下代码在我的机器上已经花费了大约15分钟

import random

def swap(i, j):
    i, j = j, i
    return i, j

def exchange(i, j):
    i, j = i - 3, j + 2
    return i, j

x, y = 15, 12
visited = {(x, y)}

for run in range(1_000_000_000):
    while x + y > 2:
        if x < 3:
            x, y = swap(x, y)
        else:
            coinflip = random.randint(0, 1)
            if coinflip == 0:
                x, y = swap(x, y)
            else:
                x, y = exchange(x, y)
        visited = visited.union({(x, y)})

    x, y = swap(x, y)    
    visited = visited.union({(x, y)})

print('Visited states:', visited)
print('Number of visited states:', len(visited))

被访问国:{(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

full state space

这是一条访问52个州的路线。绿色的X是起点,每个蓝色的圆圈表示一个访问状态。因为我们从引用的证据中知道,n<;=52,这证明了n=52

52 states visited in one path

相关问题 更多 >