八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
广度优先搜索算法流程:
1. 把起始节点放到OPEN表中(如果该起始节点为一目标节点,则求得一个解答)。
2. 如果OPEN是个空表,则没有解,失败退出;否则继续。
3. 把第一个节点(节点n)从OPEN表移出,并把它放入CLOSED的扩展节点表中。 扩展节点n。如果没有后继节点,则转向上述第(2)步。
4. 把n的所有后继节点放到OPEN表末端,并提供从这些后继节点回到n的指针。
5. 如果n的任一个后继节点是个目标节点,则找到一个解答,成功退出;否则转向第(2)步。
package com.Mytest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
public class test {//广度优先搜索
class EightNumNode{
int[][] numMap; //eight num map
int x; //the space coordinate in lateral
int y; //the space coordinate in vertical
int parentID; //the ID of parent(the ID is the index in the closeList)
int selfID; //the ID of itself
}
public static EightNumNode beginStat;
public static EightNumNode endStat;
public static Queue<EightNumNode> openList;
public static ArrayList<EightNumNode> closeList;
public static Stack<EightNumNode> pathStack;
public int findSpaceX(int[][] M){
for(int i=0; i<M.length; i++)
for(int j=0; j<M[0].length; j++)
if(M[i][j] == 0)
return i;
return -1;
}
public int findSpaceY(int[][] M){
for(int i=0; i<M.length; i++)
for(int j=0; j<M[0].length; j++)
if(M[i][j] == 0)
return j;
return -1;
}
public boolean checkSame(int[][] A, int[][] B){
for(int i=0; i<A.length; i++)
for(int j=0; j<A[0].length; j++)
if(A[i][j] != B[i][j])
return false;
return true;
}
public void printMap(int[][] M){
for(int i=0; i<M.length; i++){
for(int j=0; j<M[0].length; j++){
System.out.print(M[i][j]+" ");
}
System.out.println();
}
}
public boolean expendPointN(EightNumNode par){
if(par.y-1 >= 0){//move left
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x][par.y-1];
son.numMap[par.x][par.y-1] = 0;
son.x = par.x;
son.y = par.y-1;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.offer(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.offer(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
if(par.x-1 >= 0){//move up
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x-1][par.y];
son.numMap[par.x-1][par.y] = 0;
son.x = par.x-1;
son.y = par.y;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.offer(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.offer(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
if(par.y+1 < 3){//move right
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x][par.y+1];
son.numMap[par.x][par.y+1] = 0;
son.x = par.x;
son.y = par.y+1;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.offer(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.offer(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
if(par.x+1 < 3){//move down
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x+1][par.y];
son.numMap[par.x+1][par.y] = 0;
son.x = par.x+1;
son.y = par.y;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.offer(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.offer(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
return false;
}
public void driver(int[][] beginM, int[][] endM){
openList = new LinkedList<test.EightNumNode>();
closeList = new ArrayList<test.EightNumNode>();
pathStack = new Stack<test.EightNumNode>();
//set the begin state
beginStat = new EightNumNode();
beginStat.numMap = beginM;
beginStat.x = findSpaceX(beginM);
beginStat.y = findSpaceY(beginM);
beginStat.parentID = -1;
//set the end state
endStat = new EightNumNode();
endStat.numMap = endM;
endStat.x = findSpaceX(endM);
endStat.y = findSpaceY(endM);
endStat.parentID = -1;
openList.offer(beginStat);
EightNumNode n;
int idcount = 0;
while (!openList.isEmpty()) {
n = openList.remove();
closeList.add(n);
n.selfID = idcount++;
if (expendPointN(n)) {
System.out.println("Success!!!");
break;
}
}
if (openList.isEmpty()) {
System.out.println("Fail!!!");
} else {
int tempParID = pathStack.peek().parentID;
EightNumNode tempNode;
while(tempParID != -1){
tempNode = closeList.get(tempParID);
pathStack.push(tempNode);
tempParID = tempNode.parentID;
}
System.out.println("The path from beginning to end:");
int i=0;
while(!pathStack.empty()){
System.out.println("step "+(i++));
printMap(pathStack.pop().numMap);
System.out.println();
}
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Please input the beginMAP:");
int[][] beginMap = new int[3][3];
for(int i=0; i<beginMap.length; i++)
for(int j=0; j<beginMap[0].length; j++)
beginMap[i][j] = scan.nextInt();
System.out.println("Please input the endMAP:");
int[][] endMap = new int[3][3];
for(int i=0; i<endMap.length; i++)
for(int j=0; j<endMap[0].length; j++)
endMap[i][j] = scan.nextInt();
/* int[][] beginMap = { { 2, 8, 3 },
{ 1, 0, 4 },
{ 7, 6, 5 } };
int[][] endMap = { { 1, 2, 3 },
{ 8, 0, 4 },
{ 7, 6, 5 } };
*/
test t = new test();
if(t.checkSame(beginMap, endMap)){
System.out.println("The beginMap and endMap are the same.");
System.out.println("No need to move!");
}
else{
t.driver(beginMap, endMap);
}
}
}
深度优先搜索算法流程:
1. 把起始节点放到OPEN表中(如果该起始节点为一目标节点,则求得一个解答)。
2. 如果OPEN是个空表,则没有解,失败退出;否则继续。
3. 把第一个节点(节点n)从OPEN表移出,并把它放入CLOSED的扩展节点表中。
4. 考察节点n是否为目标节点,若是,则找到问题的解,用回溯法求解路径,退出
5. 如果没有后继节点,则转向上述第(2)步。
6. 扩展节点n,把n的所有后继节点放到OPEN表前端,并提供从这些后继节点回到n的指针。转向第(2)步。
package com.Mytest;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
public class test2 {//深度优先搜索
class EightNumNode{
int[][] numMap;
int x;
int y;
int parentID;
int selfID;
}
public static EightNumNode beginStat;
public static EightNumNode endStat;
public static Stack<EightNumNode> openList;
public static ArrayList<EightNumNode> closeList;
public static Stack<EightNumNode> pathStack;
public int findSpaceX(int[][] M){
for(int i=0; i<M.length; i++)
for(int j=0; j<M[0].length; j++)
if(M[i][j] == 0)
return i;
return -1;
}
public int findSpaceY(int[][] M){
for(int i=0; i<M.length; i++)
for(int j=0; j<M[0].length; j++)
if(M[i][j] == 0)
return j;
return -1;
}
public boolean checkSame(int[][] A, int[][] B){
for(int i=0; i<A.length; i++)
for(int j=0; j<A[0].length; j++)
if(A[i][j] != B[i][j])
return false;
return true;
}
public void printMap(int[][] M){
for(int i=0; i<M.length; i++){
for(int j=0; j<M[0].length; j++){
System.out.print(M[i][j]+" ");
}
System.out.println();
}
}
public boolean expendPointN(EightNumNode par){
if(par.x+1 < 3){//move down
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x+1][par.y];
son.numMap[par.x+1][par.y] = 0;
son.x = par.x+1;
son.y = par.y;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.push(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.push(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
if(par.y+1 < 3){//move right
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x][par.y+1];
son.numMap[par.x][par.y+1] = 0;
son.x = par.x;
son.y = par.y+1;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.push(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.push(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
if(par.x-1 >= 0){//move up
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x-1][par.y];
son.numMap[par.x-1][par.y] = 0;
son.x = par.x-1;
son.y = par.y;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.push(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.push(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
if(par.y-1 >= 0){//move left
EightNumNode son = new EightNumNode();
son.numMap = new int[3][3];
for(int i=0; i<par.numMap.length; i++)
for(int j=0; j<par.numMap[0].length; j++)
son.numMap[i][j] = par.numMap[i][j];
son.numMap[par.x][par.y] = son.numMap[par.x][par.y-1];
son.numMap[par.x][par.y-1] = 0;
son.x = par.x;
son.y = par.y-1;
son.parentID = par.selfID;
if(par.parentID == -1){
openList.push(son);
}
else {
if(!checkSame(son.numMap, closeList.get(par.parentID).numMap))
openList.push(son);
}
if(checkSame(son.numMap, endStat.numMap)){
pathStack.push(son);
return true;
}
}
return false;
}
public void driver(int[][] beginM, int[][] endM){
openList = new Stack<EightNumNode>();
closeList = new ArrayList<EightNumNode>();
pathStack = new Stack<EightNumNode>();
beginStat = new EightNumNode();
beginStat.numMap = beginM;
beginStat.x = findSpaceX(beginM);
beginStat.y = findSpaceY(beginM);
beginStat.parentID = -1;
endStat = new EightNumNode();
endStat.numMap = endM;
endStat.x = findSpaceX(endM);
endStat.y = findSpaceY(endM);
endStat.parentID = -1;
openList.push(beginStat);
EightNumNode n;
int idcount = 0;
while (!openList.isEmpty()) {
n = openList.pop();
closeList.add(n);
n.selfID = idcount++;
if (expendPointN(n)) {
System.out.println("Success!!!");
break;
}
}
if (openList.isEmpty()) {
System.out.println("Fail!!!");
} else {
int tempParID = pathStack.peek().parentID;
EightNumNode tempNode;
while(tempParID != -1){
tempNode = closeList.get(tempParID);
pathStack.push(tempNode);
tempParID = tempNode.parentID;
}
System.out.println("The path from beginning to end:");
int i=0;
while(!pathStack.empty()){
System.out.println("step "+(i++));
printMap(pathStack.pop().numMap);
System.out.println();
}
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Please input the beginMAP:");
int[][] beginMap = new int[3][3];
for(int i=0; i<beginMap.length; i++)
for(int j=0; j<beginMap[0].length; j++)
beginMap[i][j] = scan.nextInt();
System.out.println("Please input the endMAP:");
int[][] endMap = new int[3][3];
for(int i=0; i<endMap.length; i++)
for(int j=0; j<endMap[0].length; j++)
endMap[i][j] = scan.nextInt();
/* int[][] beginMap = { { 2, 8, 3 },
{ 1, 0, 4 },
{ 7, 6, 5 } };
int[][] endMap = { { 1, 2, 3 },
{ 8, 0, 4 },
{ 7, 6, 5 } };
*/
test t = new test();
if(t.checkSame(beginMap, endMap)){
System.out.println("The beginMap and endMap are the same.");
System.out.println("No need to move!");
}
else{
t.driver(beginMap, endMap);
}
}
}
直接运行程序,输入开始的八数码状态图(源),和结束的八数码状态图(目标),会打印出相应的从源图到目标图移动的路径上的所有节点,也就是打印了一种成功的解法。
广度优先搜索和深度优先搜索的代码结构基本一致,主要区别在
广度:open表用队列,扩展节点N的顺序是左上右下 深度:open表用栈,扩展节点N的顺序是下右上左
有个很好的PPT可以帮助理解 http://wenku.baidu.com/view/6fb5e40ebb68a98271fefa4b.html