2013-03-06 124 views
0

我知道这个问题以前已经问过,但我根本看不到答案。我应该写递归迷宫解决方案,这里是我迄今所做的:递归求解迷宫

import java.awt.Color; 
import java.util.ArrayList; 

public class RecursiveMazeSolution implements MazeSolver { 
boolean[][] marked; 
ArrayList<Maze.Door> solutionPath = new ArrayList<>(); 

public ArrayList<Maze.Door> solveMaze(int startRow, int finishRow, int startCol, int finishCol, Maze maze) { 
    marked = new boolean[maze.getRows()][maze.getColumns()]; 
    return solveMaze(startRow, finishRow, startCol, finishCol, maze, marked); 
} 

public ArrayList<Maze.Door> solveMaze(int startRow, int finishRow, int startCol, int finishCol, Maze maze, boolean[][] marked) { 
    System.out.println(startRow + " " + startCol + " " + finishRow + " " + finishCol); 
    if(startRow < 0 || startCol < 0 || startRow > maze.getRows() - 1|| startCol > maze.getColumns() - 1) return null; 
    if(marked[startRow][startCol]) { 
     System.out.println("I'm inside marked if"); 
     return null; 
    } 

    marked[startRow][startCol] = true; 
    if(startRow == finishRow && startCol == finishCol) { 
     solutionPath.add(new Maze.Door(startRow, startCol, Maze.NO_DIRECTION, Color.RED)); 
     return solutionPath; 
    } 

    if(solveMaze(startRow - 1, finishRow, startCol, finishCol,maze, marked) != null && !maze.isClosed(startRow, startCol, Maze.NORTH)) { 
     solutionPath.add(new Maze.Door(startRow, startCol, Maze.NORTH, Color.RED)); 
     return solutionPath; 
    } 
    if(solveMaze(startRow + 1, finishRow, startCol, finishCol,maze, marked) != null && !maze.isClosed(startRow, startCol, Maze.SOUTH)){ 
     solutionPath.add(new Maze.Door(startRow, startCol, Maze.SOUTH, Color.RED)); 
     return solutionPath; 
    } 
    if(solveMaze(startRow, finishRow, startCol - 1, finishCol,maze, marked) != null && !maze.isClosed(startRow, startCol, Maze.WEST)){ 
     solutionPath.add(new Maze.Door(startRow, startCol, Maze.WEST, Color.RED)); 
     return solutionPath; 
    } 
    if(solveMaze(startRow, finishRow, startCol + 1, finishCol,maze, marked) != null && !maze.isClosed(startRow, startCol, Maze.EAST)){ 
     solutionPath.add(new Maze.Door(startRow, startCol, Maze.EAST, Color.RED)); 
     return solutionPath; 
    } 

    return null; 
} 


} 

这是对我所提供的迷宫类:我觉得我在

import java.io.Serializable; 
import java.awt.Color; 

public class Maze implements Serializable { 

/** 
* 
*/ 
private static final long serialVersionUID = -787488019846627488L; 
/** 
* the north wall of a room 
*/ 
public static final int NORTH = 0; 
/** 
* the east wall of a room 
*/ 
public static final int EAST = 1; 
/** 
* the south wall of a room 
*/ 
public static final int SOUTH = 2; 
/** 
* the west wall of a room 
*/ 
public static final int WEST = 3; 
/** 
* No direction from a room 
*/ 
public static final int NO_DIRECTION = 4; 
private static String[] walls = {"North", "East", "South", "West"}; 
private Room[][] rooms; 

/** 
* Constructor 
* @param rows is the number of rows in the maze 
* @param columns is the number of columns in the maze 
*/ 
public Maze(int rows, int columns) { 
    rooms = new Room[rows][columns]; 
    for (int i = 0; i < rows; i++) { 
     for (int j = 0; j < columns; j++) { 
      rooms[i][j] = new Room(); 
     } // end for 
    } // end for 
} 

/** 
* rows accessor 
* @return the number of rows in the maze 
*/ 
public int getRows() { 
    return rooms.length; 
} 

/** 
* columns accessor 
* @return the number of columns in the maze 
*/ 
public int getColumns() { 
    return rooms[0].length; 
} 

/** 
* Checks to see if a wall is closed 
* @param row the row number 
* @param column the column number 
* @param wall the wall number 
* @return true if wall is closed; false if it is open 
*/ 
public boolean isClosed(int row, int column, int wall) { 
    return rooms[row][column].closed[wall]; 
} 

/** 
* Opens the wall 
* @param row the row number 
* @param column the column number 
* @param wall the wall number 
*/ 
public void setOpen(int row, int column, int wall) { 
    rooms[row][column].closed[wall] = false; 
} 

/** 
* Closes the wall 
* @param row the row number 
* @param column the column number 
* @param wall the wall number 
*/ 
public void setClosed(int row, int column, int wall) { 
    rooms[row][column].closed[wall] = true; 
} 

public static class Door { 

    int row; 
    int column; 
    int wall; 
    Color color; 

    public Door(int row, int column, int wall, Color color) { 
     this.row = row; 
     this.column = column; 
     this.wall = wall; 
     this.color = color; 
    } // end constructor 

    public boolean equals(Object x) { 
     if (x == null) return false; 
     if (!(x.getClass().equals(this.getClass()))) { 
      return false; 
     } 
     Door door = (Door) x; 
     return row == door.row && column == door.column && wall == door.wall && color.equals(door.color); 
    } // end equal 

    public int hashCode() { 
     return row + column + wall + color.hashCode(); 
    } 

    public String toString() { 
     return row + " " + column + " " + walls[wall] + "\n"; 
    } // end toString() 
} // end Door 

private class Room implements Serializable { 

    boolean[] closed; 

    Room() { 
     closed = new boolean[4]; 
     for (int i = 0; i < 4; i++) { 
      closed[i] = true; 
     } // end for 
    } 
} // end Room 
} // end Maze 

正确的方法来解决方案,但我的程序只是递归运行一段时间,然后发现没有解决方案的迷宫。另外,如果我让我的程序忽略“墙”,它可以找到一个解决方案(在很多递归调用之后),但它不应该忽略墙。任何人都可以告诉我我做错了什么?

回答

1

基于快速浏览一下你的代码,我认为问题在于你没有取消标记solveMaze访问了正方形。当您输入该函数时,您将标记为方块,表示您无法再次访问它。但是在返回之前,您需要将其标记为空闲。

考虑到这一点之后,似乎通常不应该是一个问题,因为在确定没有通过该方块的解决方案路径后,您将取消标记方块。

然后我意识到你正在做的墙测的递归调用。这意味着您正在通过墙壁寻找解决方案,然后放弃解决方案,因为墙上有一堵墙。同时,您将所有广场标记为已访问过,并且无处寻找有效的解决方案。

你需要测试之前递归墙壁,如果有一堵墙不做递归。短路评价应足以在这里(通过重新排序在if声明条款):

if(!maze.isClosed(startRow, startCol, Maze.NORTH) && 
    solveMaze(startRow-1, finishRow, startCol, finishCol,maze, marked) != null) 

顺便说一句,有没有必要通过marked作为参数。这是一个班级成员。

+0

谢谢,我试过了,但没有帮助。我做的是: 标记为[startRow] [startCol] = false; 之前返回solutionPath中的最后一条if语句。这是你的意思吗? – GullDe 2013-03-06 09:25:29

+0

不,我的意思是,如果没有路径,你就会取消标记。也就是说,就在函数的最后一个'return null'之前。如果您在递归调用之前检查了墙,那么这不会成为这样的问题。但事实证明,你正在解决的迷宫很多(可能数千次)比你应该多,但是然后意识到你的解决方案是无效的,因为它依赖穿越墙壁。 – paddy 2013-03-06 18:57:26

+0

我已更新我的答案以包含此信息。 – paddy 2013-03-06 19:06:40