Java *8拼图的运行时间太长
如果这是一个很长的问题,我很抱歉,但我不确定我的a*8拼图java代码是否有效。。。我发现我的代码对于简单的输入运行得很好(很容易平均),但我不知道它是否在最坏的情况下工作 我试图修改我的代码,以使用每个节点的曼哈顿距离作为我的启发式函数,我的代码即使在最坏的情况下也能工作,但它只是需要太长时间。。。当我使用“错位瓷砖数量”作为启发式函数时,与使用曼哈顿距离相比,我的代码运行简单到平均情况所需的时间更长。即使在15分钟后,它也不能为最坏情况提供解决方案 注:在最坏的情况下,一个8字谜的解题步骤不超过31步 。。。以下是我的代码的主要功能:Java *8拼图的运行时间太长,java,a-star,heuristics,Java,A Star,Heuristics,如果这是一个很长的问题,我很抱歉,但我不确定我的a*8拼图java代码是否有效。。。我发现我的代码对于简单的输入运行得很好(很容易平均),但我不知道它是否在最坏的情况下工作 我试图修改我的代码,以使用每个节点的曼哈顿距离作为我的启发式函数,我的代码即使在最坏的情况下也能工作,但它只是需要太长时间。。。当我使用“错位瓷砖数量”作为启发式函数时,与使用曼哈顿距离相比,我的代码运行简单到平均情况所需的时间更长。即使在15分钟后,它也不能为最坏情况提供解决方案 注:在最坏的情况下,一个8字谜的解题步骤不
List<Node> nodeList = new ArrayList<Node>();
nodeList.add(startNode); //"Node startNode" contains the root node of the tree that will be produced
Node currentNode = null;
while (1 == 1) {
//THIS SECTION FINDS THE LEAF NODE WITH THE LEAST f(n)
currentNode = null;
for (Node pickNode : nodeList) {
if (pickNode.isLeaf == true) {
if (currentNode == null)
currentNode = pickNode;
else if (pickNode.fn < currentNode.fn){
currentNode = pickNode;
}
}
}
/*-----------------------------------------------------------*/
//BREAK THE LOOP WHEN THE SOLUTION IS FOUND
if (Arrays.deepEquals(currentNode.state, goalState))
break;
/*-----------------------------------------------------------*/
else {
int xcheck = currentNode.zeroX;
int ycheck = currentNode.zeroY;
int switcher;
int approve = 1;
/*-----------------------------------------------------------*/
//THE FOLLOWING LINES DETERMINES WHICH CHILDREN CAN BE PRODUCED BY A NODE
if ((ycheck - 1) >= 0) {
int subState[][] = new int [3][];
subState[0] = currentNode.state[0].clone();
subState[1] = currentNode.state[1].clone();
subState[2] = currentNode.state[2].clone();
switcher = subState[ycheck-1][xcheck];
subState[ycheck-1][xcheck] = 0;
subState[ycheck][xcheck] = switcher;
Node checkerNode = new Node();
checkerNode = currentNode;
while (checkerNode != null) {
if (Arrays.deepEquals(subState, checkerNode.state)) {
approve = 0;
break;
}
checkerNode = checkerNode.parentNode;
}
if (approve != 0) {
Node childNode = new Node();
childNode.state = subState;
childNode.totalPath = currentNode.totalPath + "*" + "up";
childNode.gn = currentNode.gn + 1;
childNode.hn = computeHn(childNode.state, goalState);
childNode.fn = childNode.gn + childNode.hn;
childNode.isLeaf = true;
childNode.parentNode = currentNode;
childNode.zeroX = xcheck;
childNode.zeroY = ycheck-1;
nodeList.add(childNode);
}
}
approve = 1;
/*-----------------------------------------------------------*/
if ((ycheck + 1) <= 2) {
//same logic with: if (ycheck-1 >= 0)
}
approve = 1;
/*-----------------------------------------------------------*/
if ((xcheck + 1) <= 2) {
//same logic with: if (ycheck-1 >= 0)
}
approve = 1;
/*-----------------------------------------------------------*/
if ((xcheck - 1) >= 0) {
//same logic with: if (ycheck-1 >= 0)
}
approve = 1;
}
currentNode.isLeaf = false;
}
这是给定的矩阵,或“开始状态”矩阵(在最坏的情况下,至少可以用31个移动来回答):
- 806
- 5 4 7
- 2 3 1
- 0112
- 3 4 5
- 678
- 5 8 6
- 271
- 3 0 4//此矩阵可从前面提到的开始状态矩阵中访问
。。。谢谢那些愿意帮忙的人!。。。如果有点长,我很抱歉,但我认为我应该发布代码,而不是仅仅说明代码的逻辑,因为我可能在实现逻辑时出错…曼哈顿距离会更快,因为这是一种更好的启发式方法。30秒是等待一段时间的解决方案,尤其是C++,但这并不完全荒谬。然而,即使对于一个不太好的启发来说,15分钟也是如此 如果我正确地解释了您的代码,
checkerNode
循环将通过遍历整个路径来检查当前正在探索的路径中是否已经存在此状态。这是相当低效的(O(log(n)ish),我认为)。如果你维护一个你已经扩展的状态字典,你可以把它降到常数时间
可能还有其他微妙的低效,但我怀疑这会大大加快代码的速度
编辑以解释词典:
字典是一种数据结构,允许您快速查找元素是否存在
对于大多数数据结构,如果要查找具有给定值的元素,则必须将该值与已存储在结构中的每个元素进行比较(如将checkerNode与所有前置节点进行比较的方式)。问题是,当您在数据结构中存储越来越多的内容时,这个过程将花费越来越长的时间。字典的情况并非如此,因为字典使用一种称为哈希表的东西来立即转到给定元素(如果存在)的存储位置。然后,如果元素在那里,您就知道它在数据结构中,如果不是,您就知道它不是
字典通常用于将给定的键映射到关联的值,但这里我们并不真正关心该功能。我们只想知道给定的键是否在字典中,因此我们可以将值设置为我们想要的任何值(通常我只存储布尔值“True”,或者如果需要再次找到它,则存储指向节点的指针)。在C++中,内置字典类是.< /p>
要在代码中使用它,您可以大致执行以下操作:
首先,初始化映射对象
std::map<char,int> already_explored;
继续执行程序,直到找到下一个状态,你想知道它是否已经被看到。现在我们可以在字典中查找:
if (already_explored.count(subState) > 0){
approve = 0;
}
如果按此顺序操作,您甚至不必担心检查具有相同状态的其他节点的f(n)值。A*到达的第一个肯定是到达该状态的最快方式。在查看代码之后,我可以指出两件可能会大大提高代码效率的事情:
f(n)
排序。在您的代码中,我知道您正在选择第一个循环中具有最低f(n)
的节点,遍历所有生成状态的树。这是非常低效的,因为搜索树随着算法的每次迭代而增长,而您只需要迭代该树的叶子(这些叶子是作为其他状态的继承者生成的,但没有扩展)。您最好将要以*扩展的节点存储在PriorityQueue
中。队列的第一个元素是f(n)
最低的元素,因此您不必在每次迭代中遍历所有搜索树f(n)
。
例如,如果在库中执行此操作,则以下字段将用于存储状态的“字典”:
private Map<int[][], Node> open;
private Map<int[][], Node> closed;
private Queue<Node> queue;
already_explored[currentNode.state] = True;
if (already_explored.count(subState) > 0){
approve = 0;
}
private Map<int[][], Node> open;
private Map<int[][], Node> closed;
private Queue<Node> queue;
private Node takePromising() {
// Poll until a valid state is found
Node node = queue.poll();
while (!open.containsKey(node.state())) {
node = queue.poll();
}
return node;
}