深度优先搜索学习五例之三(JAVA)

一、深度优先搜索框架一递归实现,流程如下:

public void dfs(int v) {
visited[v] = true; //访问起点v
System.out.print(v+" ");
for (int i = 0; i < k; i++) {
//递归调用搜索没有被访问过的当前节点的下一个节点(邻接点)
if (G[v][i] == 1 && !visited[i])//G[v][i]是图的邻接矩阵
dfs(i);//递归调用
}
}


例:八皇后问题是一个古老而著名的问题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
 
public class Queen{
private int n = 8;
private int a[]; //皇后放在 ( i, a[i] )
private boolean visited[]; //如果visited[i]为true,表示第i列已经被占了.
int total = 0; //方案总数

public Queen(){
a=new int[8];
visited =new boolean[8];
}


public static void main(String args[]){
Queen m=new Queen();
m.dfs(0);
System.out.println(m.getTotal());
}


private boolean can(int d){ //判断第d行的Queen可否放在第a[d]列
if( visited[a[d]] )
return false; //已经被占,则返回false
for(int i=0; i<d; i++)
if( Math.abs(a[d]-a[i])== Math.abs(i-d) )//如果第i行和第d行的Queen在同一对角线上,则返回false
return false;
return true;
}

private void output(){
int i;
total++;
System.out.print("No" +total +": ");
for(i=0; i<n; i++)
System.out.print(a[i]+1 +" ");
System.out.println();
}

public int getTotal(){
return total;
}

private void dfs(int d){
if( d>=n ){ //找到一个解并输出
output();
return;
}
for(int i=0; i<n; i++){ //每一行均有n种放法
a[d] = i; //第d行的Queen放在第i列
if(can(d)){
visited[i] = true;
dfs(d+1); //如果第d行的方法可行,就放下一行
visited[i] = false;//恢复现场
}
}
}
}



运行:
D:\java>java Queen
No1: 1 5 8 6 3 7 2 4
No2: 1 6 8 3 7 4 2 5
No3: 1 7 4 6 8 2 5 3
No4: 1 7 5 8 2 4 6 3
No5: 2 4 6 8 3 1 7 5
No6: 2 5 7 1 3 8 6 4
No7: 2 5 7 4 1 8 6 3
..........................
92

二、深度优先搜索框架二(栈实现)流程如下:
[img]http://dl.iteye.com/upload/attachment/0075/4189/c306d9b5-e619-383c-96d0-9e0362cbdf22.gif[/img]

例:深度优先搜索之迷宫问题

import java.util.Stack;

//深度优先搜索之迷宫问题
public class MazeDsf{
private static final int M=9;
private static final int N=8;

//迷宫矩阵,0为通道,1为障碍
//入口(0,0),出口(8,7)
private int[][] Matrix = {
{ 0, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 1, 0, 1, 0 },
{ 0, 0, 0, 0, 0, 0, 1, 0 },
{ 0, 1, 0, 0, 0, 0, 1, 0 },
{ 0, 1, 0, 1, 1, 0, 1, 0 },
{ 0, 1, 0, 0, 0, 0, 1, 1 },
{ 0, 1, 0, 0, 1, 0, 0, 0 },
{ 0, 1, 1, 1, 1, 1, 0, 0 } };


//标记数组,初始化为false
boolean visited[][];

public MazeDsf(){
visited=new boolean[M][N];

}

//节点
class Node{
int x;
int y;
Node(int i,int j){
x = i;
y = j;
}
}


/*坐标系统
0
----------------->y
|
|
|
|
|
V
x
*/


//右下上左
private int x_off[] = {0,1,-1,0};
private int y_off[] = {1,0,0,-1};

//输出状态
private void PrintVisited(){

for(int i = 0; i < M; ++i){
for(int j = 0; j < N; ++j)
System.out.print(visited[i][j]+" ");
System.out.println();
}
}

//输出迷宫
private void PrintMatrix(){
System.out.println("入口(0,0),出口(8,7)的迷宫,0为通道,1为障碍:");
for(int i = 0; i < M; ++i){
for(int j = 0; j < N; ++j)
System.out.print(Matrix[i][j]);
System.out.println();
}
}
//输出一条路径
//由于入栈路径是正序,要倒过来输出才是从入口到出口的路劲
private void PrintPath(Stack<Node> s){
System.out.println("一条迷宫路径:");
Stack<Node> t=new Stack<Node>();
while(!s.empty()){
t.push(s.pop());

}
while(!t.empty()){
System.out.print("("+t.peek().x+","+t.peek().y+")->");
t.pop();
}

System.out.println();
}

//深度优先搜索一条可能的路径
private void DFS(){

//1.初始化栈
Stack<Node> s=new Stack<Node>();
Node start=new Node(0,0);
s.push(start);
visited[0][0] = true;
while(!s.empty()){

//2.取得栈顶元素(注意不从栈内删除)
Node top = s.peek();
//3.遍历栈顶元素的邻节点

int i=0;
for(i = 0; i<4; ++i){ //右下上左
int nx = top.x + x_off[i];
int ny = top.y + y_off[i];
if(nx >= 0 && nx < M && ny>=0 && ny< N &&!visited[nx][ny] && Matrix[nx][ny] == 0){

//4.把满足条件的元素标记为已处理,并压入栈内
Node newNode=new Node(nx,ny);
visited[nx][ny] = true;
s.push(newNode);
//找到出口,终止搜索
if(nx == 8 && ny == 7){
//输出找到的路径
PrintPath(s);
return;
}
break;
}
}
//5.当前节点没有满足条件的邻节点,把当前栈顶元素删除
if(i == 4){
s.pop();
}
}
}


//测试代码主函数
public static void main(String args[]) {
MazeDsf maze=new MazeDsf();
maze.PrintMatrix();
maze.DFS();
}
}

运行:
D:\java>java MazeDsf
入口(0,0),出口(8,7)的迷宫,0为通道,1为障碍:
01111111
00000000
01111010
00000010
01000010
01011010
01000011
01001000
01111100
一条迷宫路径:
(0,0)->(1,0)->(1,1)->(1,2)->(1,3)->(1,4)->(1,5)->(2,5)->(3,5)->(4,5)->(5,5)->(6,
5)->(7,5)->(7,6)->(7,7)->(8,7)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值