我整天都在努力,想不出一个好的解决方案。我将实现广度优先搜索算法以解决滑动拼图。到目前为止,这是我的代码的相关部分。 (我还没有测试它是否有效,因为它不完整) 到目前为止,预计此代码将遍历所有可能性并达到目标。但是,我想不出一种方法来记录从初始状态到目标状态的路径。
private void addToQueue(PuzzleState nextPS) {
if (notVisitedAndNotNull(nextPS))
queue.add(nextPS);
}
private void solveByBFS() {
queue.clear();
queue.add(this.initialState);
long startTime = System.currentTimeMillis();
while(!queue.isEmpty()) { //TODO create a way to backtrack and get a path
if (queue.size() > maxQueueSize)
maxQueueSize = queue.size();
this.currentState = queue.poll();
if (this.currentState.equals(finalState)) { //TODO check if cannot progress any further and terminate
System.out.println("Successful! Ending Time: " + startTime);
return;
}
visited.add(this.currentState);
this.addToQueue(this.currentState.moveUp());
this.addToQueue(this.currentState.moveDown());
this.addToQueue(this.currentState.moveRight());
this.addToQueue(this.currentState.moveLeft());
}
return;
}
所以我想要一种方法来回溯跟踪并从目标节点到达初始状态,反转路径,然后在列表中打印出来。
以下是我使用的数据结构:
public class SimplePuzzleState implements PuzzleState{
private int rowSz;
private int sz;
private int zeroPos;
private int[] gameState;
@Override
public void configureState(int[] gameState) {
rowSz = (int) Math.sqrt(gameState.length);
sz = gameState.length;
zeroPos = PuzzlePropertyUtility.findZeroPosition(gameState);
this.gameState = gameState;
}
@Override
public PuzzleState moveUp() {
if (zeroPos <= rowSz - 1) {
return null;
}
this.swap(zeroPos, zeroPos - rowSz);
return this.createNewUpdatedState();
}
@Override
public PuzzleState moveDown() {
if (zeroPos >= sz - rowSz) {
return null;
}
this.swap(zeroPos, zeroPos + rowSz);
return this.createNewUpdatedState();
}
@Override
public PuzzleState moveLeft() {
if (zeroPos % rowSz <= 0) {
return null;
}
this.swap(zeroPos, zeroPos - 1);
return this.createNewUpdatedState();
}
@Override
public PuzzleState moveRight() {
if (zeroPos % rowSz >= rowSz -1) {
return null;
}
this.swap(zeroPos, zeroPos + 1);
return this.createNewUpdatedState();
}
@Override
public boolean isEqual(PuzzleState other) {
if (other != null) {
if (this.getStateArray() instanceof int[] && other.getStateArray() instanceof int[])
return (Arrays.equals(this.getStateArray(), other.getStateArray()));
}
return false;
}
@Override
public int[] getStateArray() {
return gameState;
}
private void swap(int pos1, int pos2) {
int temp = this.gameState[pos1];
this.gameState[pos1] = this.gameState[pos2];
this.gameState[pos2] = temp;
}
private PuzzleState createNewUpdatedState() {
PuzzleState newState = new SimplePuzzleState();
newState.configureState(this.getStateArray());
return newState;
}
}
这是PuzzleState接口:
public interface PuzzleState {
public void configureState(int[] gameState);
PuzzleState moveUp();
PuzzleState moveDown();
PuzzleState moveLeft();
PuzzleState moveRight();
boolean isEqual(PuzzleState other);
int[] getStateArray();
}
我考虑过向SimplePuzzleState添加一个属性以包含父节点。
但是,我无法修改它实现的接口,因为我的教师不允许这样做。因此,我无法使用链表方法回溯。有没有聪明的方法来记录正确的路径?最后,我的导师要我打印一个包含表示动作的枚举的列表。所以我必须弄清楚如何将枚举映射到函数moveUp
,moveDown
等。
提前谢谢你。我为发布这么多代码而道歉,但我真的需要建议我应该采取哪些方向。
答案 0 :(得分:1)
添加到SimplePuzzleState
另一个名为gotHereFrom
的字段,当您致电addToQueue()
时,请更新此字段(每个项目)。完成后,如果打印成功&#34;并return;
根据gotHereFrom
开始迭代并一直打印节点:
public class SimplePuzzleState implements PuzzleState{
private int rowSz;
private int sz;
private int zeroPos;
private int[] gameState;
private SimplePuzzleState gotHereFrom; // add this guy
...
protected void updateParent(SimplePuzzleState gotHereFrom) {
this.gotHereFrom = gotHereFrom;
}
...
}
和
private void addToQueue(PuzzleState nextPS) {
if (notVisitedAndNotNull(nextPS)) {
queue.add(nextPS);
nextPS.updateParent(this); // and update where we got from
}
}
迭代结果:
...
if (this.currentState.equals(finalState)) { //TODO check if cannot progress any further and terminate
System.out.println("Successful! Ending Time: " + startTime);
String path = "";
while (gotHereFrom != null) {
path += " -> " + gotHereFrom;
gotHereFrom = gotHereFrom.getGotHereFrom();
}
System.out.println(path);
return;
}
答案 1 :(得分:1)
你有正确的想法。如果您无法将父指针添加到状态,那么只需使用HashMap
之类的相同信息维护previous
。当你创建四个
子状态,添加从父级到这四个的映射。
// A map to hold parent relations.
HashMap<SimplePuzzleState, SimplePuzzleState> previous = new HashMap<>();
...
// Now change the add function.
private void addToQueue(PuzzleState parentPS, PuzzleState nextPS) {
if (notVisitedAndNotNull(nextPS)) {
queue.add(nextPS);
previous.add(nextPS, parentPS);
nextPS.updateParent(this); // and update where we got from
}
}
// Then update the calls to match:
this.addToQueue(currentState, this.currentState.moveUp());
...
当你找到目标时,就像使用父指针一样,使用哈希追溯到开始。
if (this.currentState.equals(finalState)) {
System.out.println("Successful! Ending Time: " + startTime);
System.out.println("Path back to start:");
PuzzleState state = currentState;
do {
state.print();
state = previous.get(state);
} while (state != null);
}