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

深度优先搜索DFS(Depth First Search)
(一)深度优先搜索遍历类似于树的先根遍历,是树的先根遍历的推广。

(二) 深度优先搜索就是在搜索树的每一层时始终先只扩展一个子节点,不断地向纵深前进直到不能再前进(到达叶子节点或受到深度限制)时,才从当前节点返回到上一级节点,沿另一方向又继续前进。这种方法的搜索树是从树根开始一枝一枝逐渐形成的。

深度优先搜索亦称为纵向搜索。由于一个有解的问题树可能含有无穷分枝,深度优先搜索如果误入无穷分枝(即深度无限),则不可能找到目标节点。所以,深度优先搜索策略是不完备的。
另外,应用此策略得到的解不一定是最佳解(最短路径)。
[img]http://dl.iteye.com/upload/attachment/0075/3515/b197c4f4-e1cc-305c-85bc-712d218a1a1a.jpg[/img]

三、深搜编程框架

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


//深搜框架二:栈实现
public void dfs(){
// 从顶点 v0开始搜索
visited[v0]= true; //标记已访问过
display(v0); //显示顶点信息
theStack.push(v0); // 进栈

while( !theStack.isEmpty() ) {
// 查看栈顶元素,看其是否有未访问过的邻接点
int v = getAdjUnvisitedVertex( theStack.peek() );
if(v == -1) // 没有邻接点
theStack.pop(); //出栈
else{ //有
visited[v]= true; // 标记已访问v
display(v);
theStack.push(v); // 进栈
}
}
}





四、深度优先算法求数字的全排列(使用框架一)

import java.util.Scanner;
public class PaiLie{
int n;
boolean u[]; //u[i]标识数字i是否被使用过
int ans[]; //ans排列的结果

public PaiLie(int n){
this.n=n;
u=new boolean[n+1];
ans=new int[n+1];
}

private void print(){
for (int i=0 ;i<n ;++i)
System.out.print(ans[i]+" ");
System.out.println();
}

//递归实现深度优先搜索
void dfs(int d){
if (d == n) {
print();
return;
}
for (int i=1 ; i<=n; ++i)//当前顶点的所有可能邻接点
if (!u[i]){//是邻接点
ans[d] = i;
u[i] = true;
dfs(d+1);
u[i] = false; //恢复现场
}
}
public static void main(String args[]){
Scanner in=new Scanner(System.in);
int n=in.nextInt();
PaiLie p=new PaiLie(n);
p.dfs(0);
}
}


运行:
4
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2
2 1 3 4
2 1 4 3
2 3 1 4
2 3 4 1
2 4 1 3
2 4 3 1
3 1 2 4
3 1 4 2
3 2 1 4
3 2 4 1
3 4 1 2
3 4 2 1
4 1 2 3
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1

五、农夫过河问题(使用框架二)
一个农夫带着一只狼、一只羊和一棵草,身处河的南岸。他要把这些东西全部运到北岸。问题是他面前只有一条小船,船小到只能容下他和一件物品,另外只有农夫能撑船。另外,因为狼能吃羊,而羊爱吃草,所以农夫不能留下羊和草或者狼和羊单独在河的一边,自己离开。请问农夫该采取什么方案才能将所有的东西运过河呢?

要模拟农夫过河问题,首先需要选择一个对问题中每个角色的位置进行描述的方法。
一个很方便的办法是用四位二进制数顺序分别表示农夫、羊、草和狼的位置。例如用0表示农夫或者某东西在河的南岸,1表示在河的北岸。
因此整数5(其二进制表示为0101) 表示农夫和草在河的南岸,而羊和狼在北岸。


图的遍历,设从南岸到北岸渡河,在南岸人、羊、草、狼的各个状态是(用二进制表示):0000,在北岸的时候各个状态是:1111。所以过河问题就是从0000起始状态到1111最终状态的过程。易得,总共有16种状态。然后把每一种状态看成图的一个结点,把可以连通的结点用有向边连起来,就构成的一个有向图。从0000这个结点遍历(深度优先或者广度优先)图,遍历到1111结点则找到解。

public class manriver {
private int[][] maxtri=new int[16][16];//邻接矩阵
private boolean[] order=new boolean[16];// 状态是否被访问过的数组
private stack stack=new stack();

/**
* judge the adjacency matrix elements true or false(1 or 0)
*
*/

private boolean isConnected(int x,int y){//判断x与y是否是邻接点
String X=getformatString(x);
String Y=getformatString(y);

if(X.charAt(0)==Y.charAt(0))//人必须渡河
return false;
else{
if(X.charAt(1)!=Y.charAt(1)&&X.charAt(2)!=Y.charAt(2)&&X.charAt(3)!=Y.charAt(3)){
return false;//人 羊 草 狼不能一起过
}
else if(X.charAt(1)!=Y.charAt(1)&&X.charAt(2)!=Y.charAt(2)){
return false;//人 羊 草 不能一起过
}
else if(X.charAt(1)!=Y.charAt(1)&&X.charAt(3)!=Y.charAt(3)){
return false;//人 羊 狼不能一起过
}
else if(X.charAt(2)!=Y.charAt(2)&&X.charAt(3)!=Y.charAt(3)){
return false;//人 草 狼不能一起过
}
else if(((X.charAt(0)!=X.charAt(1))&&(X.charAt(1)!=Y.charAt(1)))||
((X.charAt(0)!=X.charAt(2))&&(X.charAt(2)!=Y.charAt(2)))||
((X.charAt(0)!=X.charAt(3))&&(X.charAt(3)!=Y.charAt(3)))){
return false;//羊、草、 狼分别在人的对岸,羊、草、狼不可能直接回到人这一边
}
return true;
}
}
/**
*
* produce the adjacency matrix
*
*/
public void makeMaxtri(){
for(int i=0;i< 16;i++){
for(int j=0;j< 16;j++){
if(isConnected(i, j))
{ maxtri[i][j]=1;
}
else maxtri[i][j]=0;
}
}
}
/**
*
* 得到状态的字符串表示
* 0000 四位分别代表人 羊 草 狼
*
* */
public String getformatString(int x){

String X=Integer.toBinaryString(x);//十进制转为二进制字符串
if(X.length()< 4&&X.length()>=3){
X="0"+X;
}
else if(X.length()< 3&&X.length()>=2){
X="00"+X;
}
else if(X.length()< 2&&X.length()>=1){
X="000"+X;
}
return X;
}

/**
*
* dfs arithmetic
* dfs算法
*
*/
public void dfs(){
stack.push(0);
order[0]=true;
while(!stack.isEmpty()){
if(stack.peek()==15){//状态为1111,全部过河
break;
}
int v=getUnvisitedVetex(stack.peek());
if(v==-1){
try{stack.pop();
}catch(Exception e){
e.printStackTrace();
}
}
else{

stack.push(v);
order[v]=true;
}
}
}
/**
*
*得到与输入节点相连的一个结点
*
*/
public int getUnvisitedVetex(int x){
for(int j=0;j< 16;j++){

if(maxtri[x][j]==1&&!order[j]){

String X=getformatString(j);
//合法性判断
if((X.charAt(0)!=X.charAt(1)&&X.charAt(1)==X.charAt(3))||//羊狼在一起,如0101
(X.charAt(0)!=X.charAt(1)&&X.charAt(1)==X.charAt(2))){//羊草在一起,如1000
continue;
}
else {
return j;}
}
}
return -1;
}
/**
*
* make order
*
*/
public void printOrder() throws Exception{
for(int i=0;i< stack.length()-1;i++){
int x=stack.peekByIndex(i);
int y=stack.peekByIndex(i+1);
String X=getformatString(x);
String Y=getformatString(y);
String type="";
if(X.charAt(0)=='0'){
type="过河";
}
if(X.charAt(0)=='1'){
type="回来";
}
if(X.charAt(1)!=Y.charAt(1)){
System.out.println("人带羊"+type);
}
else if(X.charAt(2)!=Y.charAt(2)){
System.out.println("人带草"+type);
}
else if(X.charAt(3)!=Y.charAt(3)){
System.out.println("人带狼"+type);
}
else{
System.out.println("人自己"+type);
}
}
}
public static void main(String[] args){
manriver manriver=new manriver();
manriver.makeMaxtri();
manriver.dfs();
try{
manriver.printOrder();
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
*
* 堆栈简单实现类
*
*/
class stack{
private int[] num;
private int value;
public stack(){
num=new int[20];
value=-1;
}
public int peek(){

return num[value];
}
public int pop() throws Exception{
if(value>=0){
return num[value--];
}
else throw new Exception("无元素!");

}
public void push(int xx){
if(value==-1){
value=0;
num[value]=xx;
}
else{
num[++value]=xx;
}
}
public int getSize(){
return value;
}
public boolean isEmpty(){
return(value< 0);
}
public int length(){
return value+1;
}
public int peekByIndex(int i)throws Exception{
if(i< value+1&&i>=0){
return num[i];
}
else throw new Exception("未找到合适元素!");
}
}


运行:
人带羊过河
人自己回来
人带狼过河
人带羊回来
人带草过河
人自己回来
人带羊过河

源码:
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值