问题
I'm having trouble randomizing the visit from a node to its neighbors, rarely is the whole graph (a MxN array, in this test 4x4) visited, I don't get what I'm doing wrong here.
import java.util.ArrayList;
class IJ {
int i;
int j;
IJ (int i,int j){
i = this.i;
j= this.j;
}
}
class Graph {
int M;
int N;
int adjacencyMatrix[][];
ArrayList <IJ> orderOfVisits;
Graph(int M,int N){
this.M=M;
this.N=N;
adjacencyMatrix=new int[M][N];
for (int i=0; i<M; i++)
for (int j=0;j<N;j++){
adjacencyMatrix[i][j]=-1; //mark all vertices as not visited
}
orderOfVisits = new ArrayList<IJ>();
}
String northOrEast () {
double lottery = Math.random();
if (lottery>0.5D) {return "north";}
else {return "south";}
}
String southOrEastOrNorth() {
double lottery=Math.random();
if (lottery<=0.33D){
return "south";
}
else if ((lottery > 0.33D) && (lottery <= 0.66D)) {
return "east";
}
else if(lottery > 0.66D)
{
return "north";
}
System.out.println("method sEn has returned null ");
return null;
}
String southOrEast(){
double lottery = Math.random();
if (lottery>0.5D) {return "south";}
else {return "east";}
}
String southOrEastOrWest() {
double lottery=Math.random();
if (lottery<=0.33D){
return "south";
}
else if ((lottery > 0.33D) && (lottery <= 0.66D)) {
return "east";
}
else if(lottery > 0.66D)
{
return "west";
}
System.out.println("method sEw has returned null ");
return null;
}
String southOrWest(){
double lottery = Math.random();
if (lottery>0.5D) {return "south";}
else {return "west";}
}
String southOrNorthOrWest() {
double lottery=Math.random();
if (lottery<=0.33D){
return "south";
}
else if ((lottery > 0.33D) && (lottery <= 0.66D)) {
return "north";
}
else if(lottery > 0.66D)
{
return "west";
}
System.out.println("method sNw has returned null ");
return null;
}
String northOrWest(){
double lottery = Math.random();
if (lottery>0.5D) {return "north";}
else {return "west";}
}
String eastOrNorthOrWest() {
double lottery=Math.random();
if (lottery<=0.33D){
return "east";
}
else if ((lottery > 0.33D) && (lottery <= 0.66D)) {
return "north";
}
else if(lottery > 0.66D)
{
return "west";
}
System.out.println("method eNw has returned null ");
return null;
}
String any() {
double lottery=Math.random();
if (lottery<=0.25D){
return "east";
}
else if ((lottery > 0.25D) && (lottery <= 0.50D)) {
return "north";
}
else if ((lottery > 0.5D) && (lottery <= 0.75D)) {
return "south";
}
else if(lottery > 0.75D)
{
return "west";
}
System.out.println("method any has returned null ");
return null;
}
String goWhere (boolean northValid, boolean southValid, boolean eastValid, boolean westValid, int i, int j){
//border cases
//left lower corner, only north and east are valid
if ((northValid==true) && (southValid==false) &&(eastValid==true) && (westValid==false))
{return northOrEast();}
//left border:
if ((northValid==true) && (southValid==true) && (eastValid==true) && (westValid==false))
{return southOrEastOrNorth();}
//upper left corner, only south and east are valid
if ((northValid==false) && (southValid==true) && (eastValid==true) && (westValid==false))
{return southOrEast();}
//upper border
if ((northValid==false) && (southValid==true) && (eastValid==true) && (westValid==true))
{return southOrEastOrWest();}
//upper right corner
if ((northValid==false) && (southValid==true) && (eastValid==false) && (westValid==true))
{return southOrWest();}
//right border
if ((northValid==true) && (southValid==true) && (eastValid==false) && (westValid==true))
{return southOrNorthOrWest();}
//lower right corner
if ((northValid==true) && (southValid==false) && (eastValid==false) && (westValid==true))
{return northOrWest();}
//bottom border
if ((northValid==true) && (southValid==false) && (eastValid==true) && (westValid==true))
{return eastOrNorthOrWest();}
//middle
if ((northValid==true) && (southValid==true) && (eastValid==true) && (westValid==true))
{return any();}
System.out.println("go where a llegado a retornar null");
return null;
}
void DFS(int i, int j){ // i,j identifies the vertex
boolean northValid= false;
boolean southValid= false;
boolean eastValid = false;
boolean westValid = false;
int iNorth, jNorth;
int iSouth, jSouth;
int iEast, jEast;
int iWest, jWest;
iNorth=i-1;
if (!(iNorth<0)) northValid=true;
iSouth=i+1;
if(!((iSouth)>=M)) southValid=true;
jEast=j+1;
if(!((jEast)>=N)) eastValid=true;
jWest= j-1;
if (!(jWest<0)) westValid=true;
if (adjacencyMatrix[i][j]==-1){ //if the vertex is unvisited
adjacencyMatrix[i][j]=0; //mark the vertex as visited
IJ ij = new IJ(i,j);
orderOfVisits.add(ij); //add the vertex to the visit list
System.out.println("Visit i,j: " + i +" " +j);
//boolean wentNorth = false;
//boolean wentSouth=false;
//boolean wentEast = false;
//boolean wentWest = false;
// if (where!=null)
for (int rows=i; rows<M; rows++)
for (int cols=j; cols<N; cols++){
//normal DFS
String where = goWhere(northValid, southValid, eastValid, westValid, i,j);
if (where.equals("north"))
{
DFS(iNorth,j);
//wentNorth=true;
}
if (where.equals("south")){
DFS(iSouth,j);
}
if(where.equals("east")){
DFS(i, jEast);
}
if (where.equals("west")){
DFS(i,jWest);
}
// if(northValid)
// {
// DFS(iNorth,j);
// }
//
// if(southValid){
// DFS(iSouth,j);
// }
//
// if(eastValid){
// DFS(i, jEast);
// }
//
// if(westValid){
// DFS(i,jWest);
// }
}
}
// boolean southValid;
// int iSouth, jSouth;
// iSouth=i+1; jSouth=j;
// if (iSouth>=M){
// southValid=false;
// }
// else {
// southValid=true;
// }
//
// boolean southUnvisited;
// if ((southValid)&&
// (adjacencyMatrix[iSouth][jSouth]==-1)){
// southUnvisited=true;
// }
// else{
// southUnvisited=false;
// }
//
//
// boolean northValid;
// int iNorth, jNorth;
// iNorth=i-1; jNorth=j;
//
// if(iNorth<0){
// northValid=false;
// }
//
// else{
// northValid=true;
// }
//
// boolean northUnvisited;
// if ((northValid)
// &&(adjacencyMatrix[iNorth][jNorth]==-1)){
// northUnvisited=true;
// }
// else {
// northUnvisited=false;
// }
//
// boolean westValid;
// int iWest, jWest;
// iWest =i; jWest=j-1;
// if (jWest<0){
// westValid=false;
// }
// else {
// westValid=true;
// }
//
// boolean westUnvisited;
//
//
// if ((westValid)&&(adjacencyMatrix[iWest][jWest]==-1))
// {
// westUnvisited=true;
// }
// else {
// westUnvisited=false;
// }
//
//
//
// boolean eastValid;
// int iEast, jEast;
// iEast=i; jEast=j+1;
// if (jEast<0){
// eastValid=false;
// }
// else{
// eastValid=true;
// }
//
// boolean eastUnvisited;
// if (eastValid&&
// (adjacencyMatrix[iEast][jEast]==-1)){
// eastUnvisited=true;
// }
// else {
// eastUnvisited=false;
// }
//
// double lottery = Math.random();
//
//
//
// boolean canVisitNorth=northUnvisited&&northValid;
// boolean canVisitSouth=southUnvisited&&southValid;
// boolean canVisitEast=eastUnvisited&&eastValid;
// boolean canVisitWest=westUnvisited&&westValid;
//
// if (lottery>0.75D)
// {
//
// if(canVisitNorth)
// DFS(iNorth, jNorth);
//
// else if(canVisitSouth)
// DFS(iSouth, jSouth);
//
// else if(canVisitEast)
// DFS(iEast, jEast);
//
// else if(canVisitWest)
// DFS(iWest, jWest);
//
// }
//
// else if(lottery < 0.25D)
// {
//
// if(canVisitSouth)
// DFS(iSouth, jSouth);
//
// else if(canVisitNorth)
// DFS(iNorth, jNorth);
//
// else if(canVisitEast)
// DFS(iEast, jEast);
//
// else if(canVisitWest)
// DFS(iWest, jWest);
//
//
// }
//
// else if((lottery >= 0.25D)&&
// (lottery<0.5D))
// {
// if(canVisitEast)
// DFS(iEast, jEast);
//
// else if(canVisitSouth)
// DFS(iSouth, jSouth);
//
// else if(canVisitNorth)
// DFS(iNorth, jNorth);
//
// else if(canVisitWest)
// DFS(iWest, jWest);
//
//
// }
//
// else if((lottery >= 0.5D)&&
// (lottery<0.75D))
// {
//
// if(canVisitWest)
// DFS(iWest, jWest);
//
// else if(canVisitEast)
// DFS(iEast, jEast);
//
// else if(canVisitSouth)
// DFS(iSouth, jSouth);
//
// else if(canVisitNorth)
// DFS(iNorth, jNorth);
//
//
// }
} //end DFS
//
}
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Graph theGraph = new Graph(3,3);
theGraph.DFS(0,0);
}
}
this code is giving me output like:
Visit i,j: 0 0
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
Visit i,j: 1 0
Visit i,j: 2 0
even though I'm validating the position of the next move (via the booleans southValid, eastValid, etc.)
回答1:
I have a suggestion to change your goWhere
method, since all directions all directions are equally weighted when it comes to choosing which way to go.
String goWhere (boolean northValid, boolean southValid, boolean eastValid, boolean westValid){
java.util.Random r = new java.util.Random();
ArrayList<String> valids = new ArrayList<String>();
if(northValid) { valids.add("north"); }
if(southValid) { valids.add("south");}
if(eastValid) { valids.add("east"); }
if(westValid) { valids.add("west"); }
if (valids.size() > 1) {
int rand = r.nextInt(valids.size());
return valids.get(rand);
} else { return null; }
}
I think you can get rid of the other direction finder methods. I think there are some bugs still in there where i or j is outside the matrix boundary, but I think this method change might remove some complications. See my note above about returning "south" in your "northOrEast" method.
Also, consider using constants for your directions. It will help prevent typos and the compiler will catch it.
public static final int NORTH = 0;
public static final int SOUTH = 1;
public static final int EAST = 2;
public static final int WEST = 3;
Then, instead of doing string comparisons, do:
if (Graph.EAST == where) { ... }
I think there is a problem setting your valid booleans. Instead of:
if (!(iNorth<0)) northValid=true;
Try:
northValid = (iNorth >= 0);
There's not necessarily a problem in the North case, but it's a little confusing testing for false if something is less than something else.
When you're comparing to M or N, you are using > to indicate it being invalid. I think South, for example if invalid if it's >= M. Or just do:
southValid = (iSouth < M);
回答2:
Add this method
private boolean boundariesOK(int i, int j) {
return i >= 0 && j >= 0 && i < this.M && j < this.N;
}
And change decision to
if (boundariesOK(i,j) && adjacencyMatrix[i][j] == -1) { // if the vertex is unvisited
Your code is trying to visit an invalid position at the Matrix (no pun intended =)).
That's a first hack. Now figure the DFS part, where your code should be able to find all positions in the grid, which it currently does not.
来源:https://stackoverflow.com/questions/5825185/java-trouble-randomizing-a-dfs-run-to-build-a-maze