稍微回顾一下历史: 从我小时候起,我就一直在玩一个非常简单的单人纸牌游戏,但我一直没有找到解决方案,老实说,我不知道是否有一个解决方案,但我想在我的电脑的帮助下找到答案.首先,让我解释一下规则:

  • 首先,你必须拿一张网格表,画一个10x10正方形的面积.
  • 接下来,你必须把第一个数字放在你的正方形上(我通常用0,0的正方形)
  • 现在,您必须开始按照特定的跳转规则从1到100进行计数(我将立即开始),并在您要跳转到的方块内注释相应的数字.
  • skip 规则是:水平或垂直方向留2个空格,对角方向只留一个空格.

问题是: 我用Python语言编写了以下(非常慢的)代码.考虑到我的解释是计算机必须探测的可能性是100!,我认为"暴力"方法将需要相当长的时间.我运行的是第11代i7,但我的Python代码只在一个内核上执行.

我如何加速我的代码和/或我如何改进算法?

以下是代码:

class Gametable:

    def __init__( self ):
        #This value contains the maximum number reched by the algorithm
        self.max_reached = 1

    def start_at( self, coordX,  coordY ):
        tmpTable = [
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
        ]
        #We do not need to check the first jump, since the table should be empty.
        if self.is_valid_move( coordX, coordY, 1, tmpTable ):
            print("Found a solution!")
        else:
            print("Found no solution :(")

    def print_table( self, table ):
        print(52*"-")
        for X in range(10):
            for Y in range(10):
                if table[ X ][ Y ] == 0:
                    print("|    ", end="")
                else:
                    print("| {:02d} ".format( table[ X ][ Y ]), end='')
            print(" |")
            print(52*"-")
        print()


    def is_valid_move( self,  X,  Y,  counter,  table):

        # Check bounds
        if  X < 0:
            return False
        elif  X > 9:
            return False
        elif  Y < 0:
            return False
        elif  Y > 9:
            return False

        # Now check next steps
        if  table[ X ][ Y ]==0:
                table[ X ][ Y ] = counter
                if self.is_valid_move( X + 3, Y, counter+1, table ) or self.is_valid_move( X - 3, Y, counter+1, table ) or self.is_valid_move( X , Y + 3, counter+1, table ) or self.is_valid_move( X,  Y - 3, counter+1, table ) or self.is_valid_move( X + 2, Y + 2, counter+1, table ) or self.is_valid_move( X + 2, Y - 2, counter+1, table ) or self.is_valid_move( X - 2, Y + 2, counter+1, table ) or self.is_valid_move( X - 2, Y - 2, counter+1, table ):
                    return True
                else:
                    if counter > self.max_reached:
                        print("Max reached "+str(self.max_reached))
                        self.print_table(table)
                        self.max_reached = counter
                    table[X][Y] = 0 # We'll have to delete the last step if there is no further possibility
                    return False

mytable = Gametable()
mytable.start_at( 0, 0 )

这是一个游戏的例子:

Game

推荐答案

我try 了一下,并实现了Warnsdorff's rule个动作优先顺序,程序立即找到了解决方案:

def print_table(table):
    print(51*"-")
    for row in table:
        for cell in row:
            print(f"|{cell:>3} " if cell else "|    ", end='')
        print("|\n" + 51*"-")
    print()

def solve(table, x, y):
    sizey = len(table)
    sizex = len(table[0])
    size = sizey * sizex

    # Generate move list (nothing special)
    def moves(x, y):
        return [(x1, y1) 
            for x1, y1 in (
                (x + dx, y + dy)
                for dx, dy in (
                    (-3, 0), (-2,  2), (0,  3), ( 2,  2), 
                    ( 3, 0), ( 2, -2), (0, -3), (-2, -2)
                )
            )
            if 0 <= x1 < sizex and 0 <= y1 < sizey and table[y1][x1] == 0
        ]
 
    # Heuristic for evaluating a move by the number of followup moves
    def freedom(x, y):
        return len(moves(x, y))

    # Get move list sorted by heuristic (Warnsdorff's rule)
    def sortedmoves(x, y):
        return sorted((freedom(x1, y1), x1, y1) for x1, y1 in moves(x, y))

    def dfs(x, y, i):
        table[y][x] = i
        # Table completed?
        if i == size or any(dfs(x1, y1, i + 1) for _, x1, y1 in sortedmoves(x, y)):
            return True  # BINGO!
        table[y][x] = 0  # backtrack
        return False

    return dfs(x, y, 1)
    
table = [
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
]

if solve(table, 0, 0):
    print("SOLVED!")
    print_table(table)

输出:

SOLVED!
---------------------------------------------------
|  1 | 43 | 67 | 16 | 42 | 75 | 31 | 39 | 74 | 32 |
---------------------------------------------------
| 69 | 18 |  3 | 83 | 35 |  4 | 82 | 36 |  5 | 81 |
---------------------------------------------------
| 66 | 15 | 41 | 76 | 94 | 40 | 73 | 93 | 30 | 38 |
---------------------------------------------------
|  2 | 44 | 68 | 17 | 79 | 86 | 34 | 80 | 87 | 33 |
---------------------------------------------------
| 70 | 19 | 95 | 84 | 72 | 96 | 89 | 37 |  6 | 92 |
---------------------------------------------------
| 65 | 14 | 57 | 77 | 99 | 56 | 78 |100 | 29 | 60 |
---------------------------------------------------
| 23 | 45 | 71 | 26 | 90 | 85 | 27 | 91 | 88 | 10 |
---------------------------------------------------
| 54 | 20 | 98 | 55 | 58 | 97 | 50 | 59 |  7 | 49 |
---------------------------------------------------
| 64 | 13 | 24 | 63 | 12 | 25 | 62 | 11 | 28 | 61 |
---------------------------------------------------
| 22 | 46 | 53 | 21 | 47 | 52 |  8 | 48 | 51 |  9 |
---------------------------------------------------

其他起始方格

当我try 其他起始方块时,发现当从(4,2)开始时,搜索花费的时间太长.因此,我在启发式规则中增加了一个打破平局的规则(以防最小自由度被多个动作共享):我 Select 出租车距离最近的角落.事实证明,这对所有的起始职位都很有效:

def print_table(table):
    print(51*"-")
    for row in table:
        for cell in row:
            print(f"|{cell:>3} " if cell else "|    ", end='')
        print("|\n" + 51*"-")
    print()

def solve(table, x, y):
    sizey = len(table)
    sizex = len(table[0])
    size = sizey * sizex

    # Generate move list (nothing special)
    def moves(x, y):
        return [(x1, y1) 
            for x1, y1 in (
                (x + dx, y + dy)
                for dx, dy in (
                    (-3, 0), (-2,  2), (0,  3), ( 2,  2), 
                    ( 3, 0), ( 2, -2), (0, -3), (-2, -2)
                )
            )
            if 0 <= x1 < sizex and 0 <= y1 < sizey and table[y1][x1] == 0
        ]

    # Heuristic for evaluating a move by the number of followup moves
    def freedom(x, y):
        return len(moves(x, y))

    # Heuristic for breaking ties: taxicab distance to closest corner
    def cornerdistance(x, y):
        return min(x, sizex - 1 - x) + min(y, sizey - 1 - y),
    
    # Get move list sorted by heuristic (Warnsdorff's rule)
    def sortedmoves(x, y):
        return sorted((freedom(x1, y1), 
                       cornerdistance(x1, y1),
                       x1, y1) for x1, y1 in moves(x, y))

    def dfs(x, y, i):
        table[y][x] = i
        # Table completed?
        if i == size or any(dfs(x1, y1, i + 1) for _,_, x1, y1 in sortedmoves(x, y)):
            return True  # BINGO!
        table[y][x] = 0  # backtrack
        return False

    return dfs(x, y, 1)
    

# Try any starting square
for i in range(10):
    for j in range(10):
        table = [
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
            [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
        ]
        print("=====",i,j,"=================")
        if solve(table, i, j):
            print("SOLVED!")
            print_table(table)

所有100个解决方案很快就被吐到了屏幕上.

Python相关问答推荐

Python(Polars):使用之前的变量确定当前解决方案的Vector化操作

如何使用scikit-learn Python库中的Agglomerative集群算法以及集群中声明的对象数量?

如何匹配3D圆柱体的轴和半径?

Tkinter -控制调色板的位置

不允许AMBIMA API请求方法

Python中是否有方法从公共域检索搜索结果

如何调整spaCy token 化器,以便在德国模型中将数字拆分为行末端的点

如何使用Python将工作表从一个Excel工作簿复制粘贴到另一个工作簿?

Python json.转储包含一些UTF-8字符的二元组,要么失败,要么转换它们.我希望编码字符按原样保留

PywinAuto在Windows 11上引发了Memory错误,但在Windows 10上未引发

Polars:用氨纶的其他部分替换氨纶的部分

Pandas DataFrame中行之间的差异

如何并行化/加速并行numba代码?

删除marplotlib条形图上的底边

无论输入分辨率如何,稳定扩散管道始终输出512 * 512张图像

Python—转换日期:价目表到新行

在方法中设置属性值时,如何处理语句不可达[Unreacable]";的问题?

python sklearn ValueError:使用序列设置数组元素

为什么在FastAPI中创建与数据库的连接时需要使用生成器?

如何在海上配对图中使某些标记周围的黑色边框