我正在编写一个编程任务(在java中)来解决a fifteen-puzzle sort of thing。第一部分是使用深度优先搜索来找到解决方案。我希望它能够解决任意大的谜题,因此整个状态空间图可能不适合内存。相反,该算法将保留已探查状态列表以检查未来状态。算法是这样的:
如果我们处于目标状态,那么我们就完成了 如果没有,那么对于不在探索列表中的每个邻居,将其添加到探索列表中并递归深度优先搜索它。
然而,它无法正常工作。我做了一些测试,我相信问题是当我在探索列表中插入一个状态时,它实际上插入了相同的对象,这样当我稍后改变状态时,探索的列表也会发生变化。因此,程序似乎从未对某个州进行过探索。
我尝试编写一种方法来复制状态,并将副本传递给已探索的列表;但同样的问题仍然存在。但是,当我独立测试复制方法时,它似乎成功复制状态。我完全不知道问题是什么。
涉及很多代码,我不确定问题出在哪里,但这里是深度优先搜索的代码:
this class we're in is the puzzle class, and this is the depth first search
'state' keeps track of the current state we're in
'explored' is a linked list of explored states
public String depthFirst(){
state.clearPath(); // state keeps track of the path taken
explored = new LLNode(state); // create explored list with starting state
this.dfs(); // depth first search
return state.path();
}
private boolean dfs(){
if(state.equals(goal)) // if we're in the goal state, then done
return true;
char[] directions = {'n', 'e', 's', 'w'};
for(char dir : directions){ // otherwise, for each direction
if(state.move(dir)){ // if we can move in that direction, then do
if(!explored.contains(state)){ // if the new state is unexplored
explored = explored.insert(state.copy());
if(this.dfs()) // add it to explored and recurse
return true;
}
switch(dir){ // if search failed, move back and
// search the next direction
case 'n': state.move('s');
case 'e': state.move('w');
case 's': state.move('n');
case 'w': state.move('e');
}
}
}
return false; // indicates failure
}
以下是explored
的插入和包含方法:
public LLNode insert(Node gameState){
if(state == null){ // if this list node doesn't have a state
state = gameState; // then give it this one
return this;
} // otherwise tack it on the front of the list
return new LLNode(gameState, this); // and return the new head
}
public boolean contains(Node gameState){
// I had a test here that printed a message if (state == gameState)
// which was triggered when I ran the program, suggesting the problem
// I explained above
if(state.equals(gameState))
return true;
else if(next == null)
return false;
else
return next.contains(gameState);
}
这是Node类的复制功能
public Node copy(){
int[][] newState = new int[state.length][state[0].length];
for(int i = 0; i < state.length; ++i)
for(int j = 0; j < state[0].length; ++j)
newState[i][j] = state[i][j];
return new Node(newState);
}
感谢您的任何想法!
答案 0 :(得分:1)
我会检查state.move()
根本没有引用explored
- 查看提供的代码,这是我能想象的唯一可以引用相同数组的变量。
滚动您自己的数据结构(即链接列表)是否需要分配?如果没有,那么我会使用标准的Java HashSet
(或任何最适合您的要求),因为我看不出需要记住搜索的顺序,只有你已经探索过一个特定的事实。状态。
此外,是否有必要为每个探索状态存储整个数组?只记住每个探索状态的哈希值(可以存储在HashSet
中)可能更好(消耗更少的内存并且通常更有效)。
注意:你的copy()
方法假设一个NxN数组(这对你的例子来说很好,但如果拼图是矩形的话就行不了。)
答案 1 :(得分:0)