Java 滑动拼图的*启发式未按预期工作
我正在实现一个滑动拼图的解算器。在一个实现中,我使用了广度优先搜索。在第二个例子中,我使用了*。但是,A*的速度比BFS方法慢。我测量了BFS解决9x9难题的平均时间约为0.227秒,而a*的平均时间约为2秒 我对A*使用的启发式方法如下:F=G+H,其中G是无序块的数量,H是每个瓷砖到用户定义的目标状态中其假定位置的曼哈顿距离的总和 以下是比较器在优先级队列中使用的*代码的相关部分:Java 滑动拼图的*启发式未按预期工作,java,algorithm,puzzle,path-finding,Java,Algorithm,Puzzle,Path Finding,我正在实现一个滑动拼图的解算器。在一个实现中,我使用了广度优先搜索。在第二个例子中,我使用了*。但是,A*的速度比BFS方法慢。我测量了BFS解决9x9难题的平均时间约为0.227秒,而a*的平均时间约为2秒 我对A*使用的启发式方法如下:F=G+H,其中G是无序块的数量,H是每个瓷砖到用户定义的目标状态中其假定位置的曼哈顿距离的总和 以下是比较器在优先级队列中使用的*代码的相关部分: private void addToPriorityQueue(PuzzleState nextPS) {
private void addToPriorityQueue(PuzzleState nextPS) {
if (nextPS != null && !this.visited.contains(nextPS))
pQueue.add(nextPS);
}
private boolean solveByAStar() {
pQueue.clear();
pQueue.add(this.initialState);
while(!pQueue.isEmpty()) {
if (pQueue.size() > maxQueueSize)
maxQueueSize = pQueue.size();
this.currentState = pQueue.poll();
if (this.currentState.equals(finalState)) {
return true;
}
visited.add(this.currentState);
this.addToPriorityQueue(this.currentState.moveUp());
this.addToPriorityQueue(this.currentState.moveDown());
this.addToPriorityQueue(this.currentState.moveRight());
this.addToPriorityQueue(this.currentState.moveLeft());
}
return false;
}
private class puzzleStateComparator implements Comparator<PuzzleState> {
@Override
public int compare(PuzzleState o1, PuzzleState o2) {
//TODO
int[] goalState = FastPuzzleSolver.this.initialState.getStateArray();
int o1GScore = PuzzlePropertyUtility.numBlocksOutOfPlace(o1.getStateArray(), goalState);
int o2GScore = PuzzlePropertyUtility.numBlocksOutOfPlace(o2.getStateArray(), goalState);
int o1HScore = PuzzlePropertyUtility.calculateManhattanDistanceSum(o1.getStateArray(), goalState);
int o2HScore = PuzzlePropertyUtility.calculateManhattanDistanceSum(o2.getStateArray(), goalState);
return Integer.compare(o2GScore + o2HScore, o1GScore + o1HScore);
}
}
以下是计算G和H的方法:
public static int numBlocksOutOfPlace(int[] ps, int[] goal) {
int difference = 0;
for (int i : ps) {
if (ps[i] != goal[i])
difference++;
}
return difference;
}
public static int calculateManhattanDistanceSum(int[] ps, int[] goal) {
int rowSz = calculatePuzzleRowSize(ps);
int manhattanDistanceSum = 0;
for (int i = 0; i < ps.length; i++) {
for (int j = 0; j < ps.length; j++) {
if (ps[i] == goal[j])
manhattanDistanceSum += (Math.abs(i/rowSz - j/rowSz) + Math.abs(i%rowSz - j%rowSz));
}
}
return manhattanDistanceSum;
}
缓慢背后的原因是因为我的代码的效率,还是我的启发式算法有缺陷,或者两者都有
提前感谢。您是否尝试过使用VisualVM或类似工具分析代码?@chrylis我打印了这些动作,我的启发式似乎适得其反,因为需要更多的动作才能达到目标状态。您似乎在根据启发式函数对状态进行排序,但是您应该根据与源的距离+启发式函数对它们进行排序。如果你只使用启发式评分,那么很有可能它会朝着或多或少随机的方向发展。此外,您似乎正在使用两种启发式的组合?在我看来,你应该首先让它只使用一个,以确保它工作良好。更多的启发并不总是正确的,如果您添加它们,它们可能会变得不可接受,更不用说更好了。@IVlad您是指处于当前状态的源吗?@Renren29-不,源是您开始的状态。有关实现,请参阅维基百科中的A*条目。