我需要你的帮助。我不知道为什么我的代码在维度为10且脏槽位为11时会失败,请帮帮我。
package Strategies;import java.util.LinkedList;import java.util.Queue;import Cleaning.State;public class BFS {private int dirty;private Queue<State> fifo = new LinkedList<State>();private String path = "";private int num_of_expanded_states;private boolean failure = false;public BFS(State state, int dirty) { // TODO Auto-generated constructor stub this.dirty = dirty; this.num_of_expanded_states = 0; this.fifo.add(state);}public void startCleaning() { // TODO Auto-generated method stub successorFunction(fifo.element()); if(failure){ System.out.println("在最大脏槽位数的限制下没有解决方案"); return; }}public void successorFunction(State state){ int x,y,i; State temp = new State(state);// state.printRoom(); if(goalTest(state)){ printPath(state); return; } x = state.x; y = state.y; // 检查有效移动 if(x+3 <= state.room.length-1){ if(y+1 <= state.room.length-1){ if(state.room[x+1][y]==1 && state.room[x+2][y]==1 && state.room[x+3][y]==1 && state.room[x+3][y+1]==1){ for(i=1;i<=3;i++){ temp.room[x+i][y]=0; } temp.room[x+i-1][y+1]=0; temp.x = x+i-1; temp.y = y+1; temp.father = new State(state); temp.action = "3"; fifo.add(temp); } } temp = new State(state); if(y-1 >= 0){ if(state.room[x+1][y]==1 && state.room[x+2][y]==1 && state.room[x+3][y]==1 && state.room[x+3][y-1]==1){ for(i=1;i<=3;i++){ temp.room[x+i][y]=0; } temp.room[x+i-1][y-1]=0; temp.x = x+i-1; temp.y = y-1; temp.father = new State(state); temp.action = "1"; fifo.add(temp); } } } temp = new State(state); if(x-3 >= 0){ if(y+1 <= state.room.length-1){ if(state.room[x-1][y]==1 && state.room[x-2][y]==1 && state.room[x-3][y]==1 && state.room[x-3][y+1]==1){ for(i=1;i<=3;i++){ temp.room[x-i][y]=0; } temp.room[x-i+1][y+1]=0; temp.x = x-i+1; temp.y = y+1; temp.father = new State(state); temp.action = "5"; fifo.add(temp); } } temp = new State(state); if(y-1 >= 0){ if(state.room[x-1][y]==1 && state.room[x-2][y]==1 && state.room[x-3][y]==1 && state.room[x-3][y-1]==1){ for(i=1;i<=3;i++){ temp.room[x-i][y]=0; } temp.room[x-i+1][y-1]=0; temp.x = x-i+1; temp.y = y-1; temp.father = new State(state); temp.action = "7"; fifo.add(temp); } } } temp = new State(state); if(y+3 <= state.room.length-1){ if(x+1 <= state.room.length-1){ if(state.room[x][y+1]==1 && state.room[x][y+2]==1 && state.room[x][y+3]==1 && state.room[x+1][y+3]==1){ for(i=1;i<=3;i++){ temp.room[x][y+i]=0; } temp.room[x+1][y+i-1]=0; temp.x = x+1; temp.y = y+i-1; temp.father = new State(state); temp.action = "2"; fifo.add(temp); } } temp = new State(state); if(x-1 >= 0){ if(state.room[x][y+1]==1 && state.room[x][y+2]==1 && state.room[x][y+3]==1 && state.room[x-1][y+3]==1){ for(i=1;i<=3;i++){ temp.room[x][y+i-1]=0; } temp.room[x-1][y+i-1]=0; temp.x = x-1; temp.y = y+i-1; temp.father = new State(state); temp.action = "4"; fifo.add(temp); } } } temp = new State(state); if(y-3 >= 0){ if(x+1 <= state.room.length-1){ if(state.room[x][y-1]==1 && state.room[x][y-2]==1 && state.room[x][y-3]==1 && state.room[x+1][y-3]==1){ for(i=1;i<=3;i++){ temp.room[x][y-i]=0; } temp.room[x+1][y-i+1]=0; temp.x = x+1; temp.y = y-i+1; temp.father = new State(state); temp.action = "0"; fifo.add(temp); } } temp = new State(state); if(x-1 >= 0){ if(state.room[x][y-1]==1 && state.room[x][y-2]==1 && state.room[x][y-3]==1 && state.room[x-1][y-3]==1){ for(i=1;i<=3;i++){ temp.room[x][y-i]=0; } temp.room[x-1][y-i+1]=0; temp.x = x-1; temp.y = y-i+1; temp.father = new State(state); temp.action = "6"; fifo.add(temp); } } } num_of_expanded_states = num_of_expanded_states+1; // return fifo.remove(); if(fifo.isEmpty()){ failure = true; return; } else{ successorFunction(fifo.element()); }}public boolean goalTest(State state){ int counter = 0; for (int i=0;i<state.room.length;i++){ for (int j=0;j<state.room.length;j++){ if(state.room[i][j] == 1){ counter++; } } } if(counter <= dirty){ return true; } else{ return false; }}public int pathCost(String path){ if(path.equals(null)){ return 0; } path.split("(?!^)"); return path.length();}public void printPath(State goal_state){ System.out.println(calculatePath(goal_state)); System.out.println("扩展节点的数量为: "+num_of_expanded_states);}public String calculatePath(State state){ if(state.father==null){ return path; } return calculatePath(state.father).concat(state.action);}}
这是 State 类的代码:
package Cleaning;public class State {public long[][] room;public State father;public String action;public int x;public int y;public State(State another){ this.room = new long[another.room.length][another.room.length]; this.father = another.father; this.x = another.x; this.y = another.y; this.action = another.action; for(int i=0; i<this.room.length; i++) for(int j=0; j<this.room.length; j++) this.room[i][j] = another.room[i][j];}public State() { // TODO Auto-generated constructor stub}public void initializeState(int dimention){ int i,j; this.room = new long[dimention][dimention]; this.action = ""; this.father = new State(); father = null; this.x = dimention - 1; this.y = 0; for(i=0;i<dimention;i++){ for(j=0;j<dimention;j++){ if(i == (dimention-1) && j==0){ room[i][j] = 0; } else{ room[i][j] = 1; } } }}public void printRoom(){ for(int i=0;i<room.length;i++){ for(int j=0;j<room.length;j++){ System.out.print(room[i][j]+" "); } System.out.println(); }}}
我尝试了一切方法但无法解决这个异常,请帮帮我。谢谢你的帮助
日志如下:
Exception in thread "main" java.lang.StackOverflowError at java.util.LinkedList.removeFirst(Unknown Source)at java.util.LinkedList.remove(Unknown Source) at Strategies.BFS.successorFunction(BFS.java:195)at Strategies.BFS.successorFunction(BFS.java:201)at Strategies.BFS.successorFunction(BFS.java:201)at Strategies.BFS.successorFunction(BFS.java:201)at Strategies.BFS.successorFunction(BFS.java:201)at Strategies.BFS.successorFunction(BFS.java:201)at Strategies.BFS.successorFunction(BFS.java:201) 以上类似的行有很多,所以我无法全部列出
回答:
你可以通过将 successFunction 从递归改为迭代来解决你的堆栈溢出问题,例如:
private void successsFunction(State another) {
... else { successFunction(fifo.element()); }
}
改为
private void successFunction() { while(!fifo.isEmpty()) { another = fifo.element(); ... }}
这样可以解决堆栈溢出的问题,但可能会导致程序运行变慢或内存不足。
我认为你的真正问题是由于你标记房间已访问的方式以及每次创建新状态时复制房间状态的方式,导致你多次重复访问相同的房间。
从你的代码来看
public State(State another){ this.room = new long[another.room.length][another.room.length]; .... for(int i=0; i<this.room.length; i++) for(int j=0; j<this.room.length; j++) this.room[i][j] = another.room[i][j];}...private successFunction() { ... for(i=1;i<=3;i++){ temp.room[x][y+i]=0; }
这意味着你只标记了这些房间在这个房间及其子房间中已访问。如果我们有一个简单的房子,房间1连接到房间10和11,房间10连接到房间11、100和101,房间11连接到房间10、110和111。
- 你会访问房间1,标记为已访问,添加房间10和11 [递归] 队列=[10,11]
- 访问房间10,标记为已访问,添加房间11、100和101 [递归] 队列=[11,11,100,101]
- 访问房间11,标记为已访问,添加房间110和111 [递归] 队列=[11,100,101,110,111]
- 再次访问房间11,标记为已访问,添加房间110和111 [递归] 队列=[11,100,101,110,111,110,111]
如果你在每次 successFunction 开始时打印出你所在的房间,以及 fifo 队列中的房间,你会明白我的意思。
我建议的解决方案是只保留一个房间集合,让每个 State 引用该集合。
所以
public State(State another){ this.room = another.room; .... //for(int i=0; i<this.room.length; i++) // for(int j=0; j<this.room.length; j++) // this.room[i][j] = another.room[i][j];}