Algorithm 为A*搜索找到好的启发式

Algorithm 为A*搜索找到好的启发式,algorithm,search,graph-algorithm,a-star,Algorithm,Search,Graph Algorithm,A Star,我正在尝试为一个名为Twiddle的小益智游戏(可以找到一个带有该游戏的小程序)找到最佳解决方案。游戏有一个3x3矩阵,数字从1到9。目标是使用最少的移动量将数字按正确的顺序排列。在每次移动中,您可以顺时针或逆时针旋转2x2正方形 也就是说,如果你有这种状态 6 3 9 8 7 5 1 2 4 顺时针旋转左上角2x2的正方形,得到 8 6 9 7 3 5 1 2 4 我用a*搜索来找到最佳解决方案。My f()只是所需的旋转次数。我的启发式函数已经得出了最优解(如果我修改了它,请参见末尾的通

我正在尝试为一个名为Twiddle的小益智游戏(可以找到一个带有该游戏的小程序)找到最佳解决方案。游戏有一个3x3矩阵,数字从1到9。目标是使用最少的移动量将数字按正确的顺序排列。在每次移动中,您可以顺时针或逆时针旋转2x2正方形

也就是说,如果你有这种状态

6 3 9
8 7 5
1 2 4
顺时针旋转左上角2x2的正方形,得到

8 6 9
7 3 5
1 2 4
我用a*搜索来找到最佳解决方案。My f()只是所需的旋转次数。我的启发式函数已经得出了最优解(如果我修改了它,请参见末尾的通知),但我认为它不是你能找到的最好的。我目前的启发式算法会选取每个角点,查看角点处的数字,并计算到该数字在求解状态下所处位置的manhatten距离(这给了我将该数字带到该位置所需的旋转次数),然后将所有这些值相加。也就是说,您以上述示例为例:

6 3 9
8 7 5
1 2 4
而这个最终状态呢

1 2 3
4 5 6
7 8 9 
然后启发式执行以下操作

6 is currently at index 0 and should by at index 5: 3 rotations needed
9 is currently at index 2 and should by at index 8: 2 rotations needed
1 is currently at index 6 and should by at index 0: 2 rotations needed
4 is currently at index 8 and should by at index 3: 3 rotations needed

h = 3 + 2 + 2 + 3 = 10
此外,如果h为0,但状态不是完全有序的,则h=1

但是有一个问题,你一次旋转4个元素。所以很少有这样的情况,你可以在一个动作中完成两个(或者更多)的旋转。这意味着这些启发式方法高估了到解决方案的距离

我目前的解决方法是,简单地从计算中排除一个角,这至少解决了我的测试用例的这个问题。我没有做过任何研究,如果真的解决了这个问题,或者如果这个启发式仍然高估了一些边缘的情况

所以我的问题是:你能想出的最好的启发是什么?


(免责声明:这是一个大学项目,所以这是一点家庭作业。但如果我能想出任何资源,我都可以自由使用,所以可以问你们。我也将感谢Stackoverflow对我的帮助;)

计算距离时应考虑所有元素,而不仅仅是角元素。想象一下,所有的角元素1、3、7、9都在它们的家中,而所有其他元素都不在


可以说,处于最终状态的相邻元素在每一步中都会变得更近,因此相邻距离也可以是启发式的一部分,但其影响可能比元素到其最终状态的距离小。

简单性通常是最有效的。将九个数字(行中的第一个顺序)视为形成一个整数。该解由最小的整数i(g)=123456789表示。因此,我建议以下启发式h(s)=I(s)-I(g)。例如,h(s)=639875124-123456789

您可以从您的方法中获得一个可接受的(即,不高估的)启发,方法是将所有数字都考虑在内,然后除以4并四舍五入到下一个整数


为了改进启发式,您可以查看成对的数字。例如,如果左上角的数字1和2被交换,则至少需要3次旋转才能将其修复,这是一个比1+1更好的值。最后,你仍然需要除以4。您可以任意配对数字,甚至可以尝试所有配对,并将最佳分割为若干对。

您的启发式算法高估了距离,这意味着在某些情况下,in可能无法得到最佳解决方案。您最好希望我们不要告诉Simon您在作弊。:)@正如我写的:我知道。正因为如此,我在寻找一个更好的方法,当你在写启发式的问题时,你也在写“我的启发式函数已经导致了最优解”。所以我不确定你是否知道过高的启发式会导致非最优的解决方案。你是对的。如果把问题编辑得更清楚,你是对的。我忘了提到,如果所有角元素都在它们的家中,但总状态没有排序,那么h是1。如果我错了,请纠正我,但这对于a*来说不是一个有用的启发式方法,因为h()需要(低估)估计到目标的距离。如果不是所需的旋转,我应该使用什么作为距离测量?你说得很对。我的这个建议只是一个暗示,在其他情况下也是一个有用的技巧。然而,设计实值函数以满足a*启发式要求并不困难。例如,h(n)=(i(n)-i(g))/i(s),其中n是当前状态,g是目标状态,s是初始状态,i是我在上面的回答中定义的状态值。h(g)=0.0。但是,您需要对此进行测试。告诉我们是否找到了最佳解决方案。好的,我已经测试过了。有时似乎估计过高,因为并非每次都能找到最优解。这也会产生h()的值,约为1。有时值较高,但不够高,无法以有用的方式优化搜索。不过这是一个聪明的猛禽,谢谢。如果你只想得到保证的最优解,那么对于像这样的小问题,最简单的方法就是设置h(n)=0,这总是会被保证低估。事实上,这将为您提供广度优先搜索,如果有足够的空间存储边界集,它将始终找到最优解。这是错误的。这种启发式是不可接受的,缩小规模使其可接受会使其毫无用处。将h(x)设置为0是可行的,但它不再是A*而是DIjkstra(在本例中相当于BFS)。