我已经实现了一个能够用 A*解决n 谜题的程序。由于状态空间太大,我无法预编译它,我必须在运行时计算可能的状态。以这种方式,A* 对于 3 拼图工作正常,但对于 4 拼图可能需要太长时间。使用通过线性冲突调整的曼哈顿距离,如果最优解需要大约 25 次移动仍然很快,大约 35 需要 10 秒,对于 40 需要 180 秒。我还没有尝试更多。
我认为那是因为我必须保留所有访问过的状态,因为我使用的函数是可接受的,但(我认为)不一致(我也尝试了 Hamming 和 Gaschnig 距离等等)。由于解决方案的空间是一个图,因此启发式也必须是一致的,否则算法可能会循环或不是最优的。这就是为什么我保留所有访问过的节点(它也写在“AI:一种现代方法”一书中)。但无论如何,这个存储一点也不慢。减慢的是保持要访问的节点队列有序。
所以我决定尝试 IDA*,正如我所见,它不需要这种存储(但我仍然必须保留所有访问过的状态以避免循环)。对于需要 35 次或更少移动的解决方案,它更快,但对于 40 次移动,它要慢得多。
这是我的代码。难道我做错了什么?
public static State solveIDAStar(State initialState) {
int limit = initialState.getManhattanDistance() + 2 * initialState.getLinearConflicts();
State result = null;
while(result == null) {
visitedStates.add(initialState); // It's a global variable
result = limitedSearch(initialState, limit);
limit = newLimit;
visitedStates.clear();
}
return result;
}
public static State limitedSearch(State current, int limit) {
for(State s : current.findNext()) {
if(s.equals(GOAL)) {
s.setParent(current);
return s;
}
if(!visitedStates.contains(s)) {
s.setPathCost(current.getPathCost() + 1);
s.setParent(current);
int currentCost = s.getManhattanDistance() + 2 * s.getLinearConflicts() + s.getPathCost();
if(currentCost <= limit) {
visitedStates.add(s);
State solution = limitedSearch(s, limit);
if(solution != null)
return solution;
} else {
if(currentCost < newLimit)
newLimit = currentCost;
}
}
}
return null;
}