这是Java中实现Lee的算法。问题是回溯中的偏差(在屏幕截图上):
。
请帮忙吗?
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.JComboBox;
public class Main {
JFrame frame;
//GENERAL VARIABLES
private int cells = 20;
private int delay = 30;
private int startx = -1;
private int starty = -1;
private int finishx = -1;
private int finishy = -1;
private int tool = 0;
private int checks = 0;
private int length = 0;
private int WIDTH = 850;
private final int HEIGHT = 650;
private final int MSIZE = 600;
private int CSIZE = MSIZE/cells;
//UTIL ARRAYS
private String[] tools = {"Start","Finish","Wall", "Eraser"};
//BOOLEANS
private boolean solving = false;
//UTIL
Node[][] map;
Algorithm Alg = new Algorithm();
Random r = new Random();
//SLIDERS
JSlider size = new JSlider(1,5,4);
JSlider speed = new JSlider(0,500,delay);
//LABELS
JLabel toolL = new JLabel("Toolbox");
JLabel sizeL = new JLabel("Size:");
JLabel cellsL = new JLabel(cells+"x"+cells);
JLabel delayL = new JLabel("Delay:");
JLabel msL = new JLabel(delay+"ms");
JLabel checkL = new JLabel("Checks: "+checks);
JLabel lengthL = new JLabel("Path Length: "+length);
//BUTTONS
JButton searchB = new JButton("Search");
JButton resetB = new JButton("Reset");
JButton clearMapB = new JButton("Clear");
//DROP DOWN
JComboBox toolBx = new JComboBox(tools);
//PANELS
JPanel toolP = new JPanel();
//CANVAS
Map canvas;
public static void main(String[] args) { //MAIN METHOD
new Main();
}
public Main() { //CONSTRUCTOR
clearMap();
initialize();
}
public void clearMap() { //CLEAR MAP
finishx = -1; //RESET THE START AND FINISH
finishy = -1;
startx = -1;
starty = -1;
map = new Node[cells][cells]; //CREATE NEW MAP OF NODES
for(int x = 0; x < cells; x++) {
for(int y = 0; y < cells; y++) {
map[x][y] = new Node(3,x,y); //SET ALL NODES TO EMPTY
}
}
reset(); //RESET SOME VARIABLES
}
public void resetMap() { //RESET MAP
for(int x = 0; x < cells; x++) {
for(int y = 0; y < cells; y++) {
Node current = map[x][y];
if(current.getType() == 4 || current.getType() == 5) //CHECK TO SEE IF CURRENT NODE IS EITHER CHECKED OR FINAL PATH
map[x][y] = new Node(3,x,y); //RESET IT TO AN EMPTY NODE
}
}
if(startx > -1 && starty > -1) { //RESET THE START AND FINISH
map[startx][starty] = new Node(0,startx,starty);
map[startx][starty].setHops(0);
}
if(finishx > -1 && finishy > -1)
map[finishx][finishy] = new Node(1,finishx,finishy);
reset(); //RESET SOME VARIABLES
}
private void initialize() { //INITIALIZE THE GUI ELEMENTS
frame = new JFrame();
frame.setVisible(true);
frame.setResizable(false);
frame.setSize(WIDTH,HEIGHT);
frame.setTitle("Lee Algorithm");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
int space = 25;
int buff = 45;
toolP.setLayout(null);
toolP.setBounds(10,10,210,600);
searchB.setBounds(40,space, 120, 25);
toolP.add(searchB);
space+=buff;
resetB.setBounds(40,space,120,25);
toolP.add(resetB);
space+=buff;
clearMapB.setBounds(40,space, 120, 25);
toolP.add(clearMapB);
space+=40;
toolL.setBounds(40,space,120,25);
toolP.add(toolL);
space+=25;
toolBx.setBounds(40,space,120,25);
toolP.add(toolBx);
space+=buff;
sizeL.setBounds(15,space,40,25);
toolP.add(sizeL);
size.setMajorTickSpacing(10);
size.setBounds(50,space,100,25);
toolP.add(size);
cellsL.setBounds(160,space,40,25);
toolP.add(cellsL);
space+=buff;
delayL.setBounds(15,space,50,25);
toolP.add(delayL);
speed.setMajorTickSpacing(5);
speed.setBounds(50,space,100,25);
toolP.add(speed);
msL.setBounds(160,space,40,25);
toolP.add(msL);
space+=buff;
checkL.setBounds(15,space,100,25);
toolP.add(checkL);
space+=buff;
lengthL.setBounds(15,space,100,25);
toolP.add(lengthL);
frame.getContentPane().add(toolP);
canvas = new Map();
canvas.setBounds(230, 10, MSIZE+1, MSIZE+1);
frame.getContentPane().add(canvas);
searchB.addActionListener(new ActionListener() { //ACTION LISTENERS
@Override
public void actionPerformed(ActionEvent e) {
reset();
if((startx > -1 && starty > -1) && (finishx > -1 && finishy > -1))
solving = true;
}
});
resetB.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
resetMap();
Update();
}
});
clearMapB.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
clearMap();
Update();
}
});
toolBx.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
tool = toolBx.getSelectedIndex();
}
});
size.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
cells = size.getValue()*5;
clearMap();
reset();
Update();
}
});
speed.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
delay = speed.getValue();
Update();
}
});
startSearch(); //START STATE
}
public void startSearch() { //START STATE
if(solving)
{
Alg.LeeAlg();
}
pause(); //PAUSE STATE
}
public void pause() { //PAUSE STATE
int i = 0;
while(!solving) {
i++;
if(i > 500)
i = 0;
try {
Thread.sleep(1);
} catch(Exception e) {}
}
startSearch(); //START STATE
}
public void Update() { //UPDATE ELEMENTS OF THE GUI
CSIZE = MSIZE/cells;
canvas.repaint();
cellsL.setText(cells+"x"+cells);
msL.setText(delay+"ms");
lengthL.setText("Path Length: "+length);
checkL.setText("Checks: "+checks);
}
public void reset() { //RESET METHOD
solving = false;
length = 0;
checks = 0;
}
public void delay() { //DELAY METHOD
try {
Thread.sleep(delay);
} catch(Exception e) {}
}
class Map extends JPanel implements MouseListener, MouseMotionListener{ //MAP CLASS
public Map() {
addMouseListener(this);
addMouseMotionListener(this);
}
public void paintComponent(Graphics g) { //REPAINT
super.paintComponent(g);
for(int x = 0; x < cells; x++) { //PAINT EACH NODE IN THE GRID
for(int y = 0; y < cells; y++) {
switch(map[x][y].getType()) {
case 0:
g.setColor(Color.GREEN);
break;
case 1:
g.setColor(Color.BLUE);
break;
case 2:
g.setColor(Color.BLACK);
break;
case 3:
g.setColor(Color.WHITE);
break;
case 4:
g.setColor(Color.GRAY);
break;
case 5:
g.setColor(Color.YELLOW);
break;
}
g.fillRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
g.setColor(Color.BLACK);
g.drawRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
}
}
}
@Override
public void mouseDragged(MouseEvent e) {
try {
int x = e.getX()/CSIZE;
int y = e.getY()/CSIZE;
Node current = map[x][y];
if((tool == 2 || tool == 3) && (current.getType() != 0 && current.getType() != 1))
current.setType(tool);
Update();
} catch(Exception z) {}
}
@Override
public void mouseMoved(MouseEvent e) {}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
resetMap(); //RESET THE MAP WHENEVER CLICKED
try {
int x = e.getX()/CSIZE; //GET THE X AND Y OF THE MOUSE CLICK IN RELATION TO THE SIZE OF THE GRID
int y = e.getY()/CSIZE;
Node current = map[x][y];
switch(tool) {
case 0: { //START NODE
if(current.getType()!=2) { //IF NOT WALL
if(startx > -1 && starty > -1) { //IF START EXISTS SET IT TO EMPTY
map[startx][starty].setType(3);
map[startx][starty].setHops(-1);
}
current.setHops(0);
startx = x; //SET THE START X AND Y
starty = y;
current.setType(0); //SET THE NODE CLICKED TO BE START
}
break;
}
case 1: {//FINISH NODE
if(current.getType()!=2) { //IF NOT WALL
if(finishx > -1 && finishy > -1) //IF FINISH EXISTS SET IT TO EMPTY
map[finishx][finishy].setType(3);
finishx = x; //SET THE FINISH X AND Y
finishy = y;
current.setType(1); //SET THE NODE CLICKED TO BE FINISH
}
break;
}
default:
if(current.getType() != 0 && current.getType() != 1)
current.setType(tool);
break;
}
Update();
} catch(Exception z) {} //EXCEPTION HANDLER
}
@Override
public void mouseReleased(MouseEvent e) {}
}
class Algorithm { // ALGORITHM CLASS
public void LeeAlg() {
ArrayList<Node> priority = new ArrayList<Node>(); //CREATE A PRIORITY QUE
priority.add(map[startx][starty]); //ADD THE START TO THE QUE
while (solving) {
if (priority.size() <= 0) { //IF THE QUE IS 0 THEN NO PATH CAN BE FOUND
solving = false;
break;
}
int hops = priority.get(0).getHops() + 1; //INCREMENT THE HOPS VARIABLE
ArrayList<Node> explored = exploreNeighbors(priority.get(0), hops); //CREATE AN ARRAYLIST OF NODES THAT WERE EXPLORED
if (explored.size() > 0) {
priority.remove(0); //REMOVE THE NODE FROM THE QUE
priority.addAll(explored); //ADD ALL THE NEW NODES TO THE QUE
Update();
delay();
} else { //IF NO NODES WERE EXPLORED THEN JUST REMOVE THE NODE FROM THE QUE
priority.remove(0);
}
}
}
public ArrayList<Node> exploreNeighbors(Node current, int hops) { //EXPLORE NEIGHBORS
ArrayList<Node> explored = new ArrayList<Node>(); //LIST OF NODES THAT HAVE BEEN EXPLORED
for(int a = -1; a <= 1; a++) {
for(int b = -1; b <= 1; b++) {
int xbound = current.getX()+a;
int ybound = current.getY()+b;
if((xbound > -1 && xbound < cells) && (ybound > -1 && ybound < cells)) { //MAKES SURE THE NODE IS NOT OUTSIDE THE GRID
Node neighbor = map[xbound][ybound];
if((neighbor.getHops()==-1 || neighbor.getHops() > hops) && neighbor.getType()!=2) { //CHECKS IF THE NODE IS NOT A WALL AND THAT IT HAS NOT BEEN EXPLORED
explore(neighbor, current.getX(), current.getY(), hops); //EXPLORE THE NODE
explored.add(neighbor); //ADD THE NODE TO THE LIST
}
}
}
}
return explored;
}
public void explore(Node current, int lastx, int lasty, int hops) { //EXPLORE A NODE
if(current.getType()!=0 && current.getType() != 1) //CHECK THAT THE NODE IS NOT THE START OR FINISH
current.setType(4); //SET IT TO EXPLORED
current.setLastNode(lastx, lasty); //KEEP TRACK OF THE NODE THAT THIS NODE IS EXPLORED FROM
current.setHops(hops); //SET THE HOPS FROM THE START
checks++;
if(current.getType() == 1) { //IF THE NODE IS THE FINISH THEN BACKTRACE TO GET THE PATH
backtrace(current.getLastX(), current.getLastY(),hops);
}
}
public void backtrace(int lx, int ly, int hops) { //BACKTRACE
length = hops;
while(hops > 1) { //BACKTRACE FROM THE END OF THE PATH TO THE START
Node current = map[lx][ly];
current.setType(5);
lx = current.getLastX();
ly = current.getLastY();
hops--;
}
solving = false;
}
}
class Node {
// 0 = start, 1 = finish, 2 = wall, 3 = empty, 4 = checked, 5 = finalpath
private int cellType = 0;
private int hops;
private int x;
private int y;
private int lastX;
private int lastY;
public Node(int type, int x, int y) { //CONSTRUCTOR
cellType = type;
this.x = x;
this.y = y;
hops = -1;
}
public int getX() {return x;} //GET METHODS
public int getY() {return y;}
public int getLastX() {return lastX;}
public int getLastY() {return lastY;}
public int getType() {return cellType;}
public int getHops() {return hops;}
public void setType(int type) {cellType = type;} //SET METHODS
public void setLastNode(int x, int y) {lastX = x; lastY = y;}
public void setHops(int hops) {this.hops = hops;}
}
}
也就是说,地图上的最短路径在侧面某处,并且应该在一条直线上。代码中应纠正什么?
答案 0 :(得分:0)
问题是,根据算法,给出的答案与海峡线一样好。怪异的对角线路径和海峡所需路径都需要4个步骤才能达到目标,因此它们都是相等的。要解决这个问题,您应该增加权重。当您沿对角线移动时,跳数不一定总是增加1,而是增加1.4(sqrt(2))。这样,在对角线上移动就具有权重,并且所需的海峡路径将是最快的(就像在现实世界中一样)。