图的深度优先搜索和广度优先搜索

什么是DFS或BFS这里不详谈,重点介绍并分析几个例子。

题目来源:

http://blog.csdn.net/qq_32183461/article/details/50705953

DFS

六角填数

1.如图【1.png】所示六角形中,填入1~12的数字。

使得每条直线上的数字之和都相同。

图中,已经替你填好了3个数字,请你计算星号位置所代表的数字是多少?

请通过浏览器提交答案,不要填写多余的内容。


image.png

深度优先搜索的通用解法

http://blog.csdn.net/championlee_cs/article/details/51030336

package Chapter4;

public class SixPoint {
    static int[] array=new int[12];
    static boolean[] visitArray=new boolean[13];
    static boolean isOk(){
        int a1=array[0]+array[2]+array[5]+array[7];
        int a2=array[0]+array[3]+array[6]+array[10];
        int a3=array[7]+array[8]+array[9]+array[10];
        int a4=array[1]+array[2]+array[3]+array[4];
        int a5=array[1]+array[5]+array[8]+array[11];
        int a6=array[4]+array[6]+array[9]+array[11];
        if(a1==a2 && a2==a3 && a3==a4 && a4==a5 && a5==a6){
            return true;
        }else{
            return false;
        }
    }
    static void display(){
        System.out.println("result:"+array[5]+" and the answer is 10");
    }
    static void DFS(int order){
        if(order>11){
            if(isOk()){
                display();
            }else{
                return;
            }
        }else{
            if(order == 0 || order == 11 || order == 1){
                DFS(order+1);
                return;
            }else{
                for(int i=1;i<visitArray.length;i++){
                    if(!visitArray[i]){
                        array[order]=i;
                        visitArray[i]=true;
                        DFS(order+1);
                        //重点!!需要在此处复原
                        visitArray[i]=false;
                    }
                }
            }
        }
    }
    public static void main(String[] args) {
        //从上到下,从左到右,保存这12个数与相应位置

        array[0]=1;
        array[1]=8;
        array[11]=3;
        for (int i=0;i<visitArray.length;i++){
            visitArray[i]=false;
        }
        visitArray[1]=true;
        visitArray[8]=true;
        visitArray[3]=true;
        DFS(0);
    }
}

八皇后

package Chapter4;

public class EightQueens {
    static int N=9;
    static int[] row=new int[N];
    static int count=0;
    static boolean isOk(int a,int b){
        if(a==b || row[a]==row[b]){
            return false;
        }
       if(Math.abs(a-b)==Math.abs(row[a]-row[b])){
           return false;
       }else{
           return  true;
       }
    }
    static void display(){
        System.out.println("the result:"+count);
        count++;
        for (int i=1;i<N;i++){
            for(int j=1;j<N;j++){
                if(j==row[i]){
                    System.out.print(row[i]);
                }else{
                    System.out.print("x");
                }
            }
            System.out.println();
        }
    }
    static void dfs(int rowCount){
        if(rowCount>N-1){
            display();
            return;
        }else{
            for(int column=1;column<N;column++){
                row[rowCount]=column;
                boolean flag=true;
                for(int rows=1;rows<rowCount;rows++){
                    if(isOk(rows,rowCount)){

                    }else{
                        flag=false;
                        break;
                    }
                }
                if(flag){
                    dfs(rowCount+1);
                    row[rowCount]=0;
                }
            }


        }
    }
    public static void main(String[] args) {
        dfs(1);
    }
}

result:

image.png

拯救OIBH总部(dfs例子)

https://vijos.org/p/1294

背景

OIBH总部突然被水淹没了!现在OIBH需要你的救援……

描述

OIBH被突来的洪水淹没了>.<还好OIBH总部有在某些重要的地方起一些围墙,用号表示,而一个封闭的号区域洪水是进不去的……现在给出OIBH的围墙建设图,问OIBH总部没被淹到的重要区域(由"0"表示)有多少。

格式

输入格式

第一行是两个数,x和y(x,y<=500)
第二行及以下是一个由和0组成的xy的图。

输出格式

输出没被水淹没的OIBH总部的“0”的数量。

样例1

样例输入1


4 5
00000
00*00
0*0*0
00*00

样例输出1

1

样例2

样例输入2


5 5
*****
*0*0*
**0**
*0*0*
*****

样例输出2

5

http://www.cnblogs.com/third2333/p/6850767.html
思路:

深搜 灌水
这题 我们就相当于求 路径上不经过 * 能到达边界的点有几个
然后我就可以从边界上开始灌水,染色,遇到 * 就 return
然后就相当于 没有被洪水填到的就是 不会到边界的节点

answer:

package Chapter4;

import java.util.Scanner;

public class SaveOIBH {
    static int[] xStep={0,0,-1,1};
    static int[] yStep={-1,1,0,0};
    static int display(char[][] array){
        int count=0;
        for(int i=0;i<array.length;i++){
            for(int j=0;j<array[i].length;j++){
                if('*'!=array[i][j]){
                    count++;
                }
            }
        }
        return count;
    }
    static void dfs(int n,int m,int x,int y,char[][] array){
        char stopChar='*';
        if(n<0 || m<0 || n>x-1 || m>y-1){
            return;
        }
        if(array[n][m]==stopChar){
            return;
        }
        array[n][m]=stopChar;
        for(int i=0;i<4;i++){
            dfs(n+xStep[i],m+yStep[i],x,y,array);
        }

    }
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        int x=in.nextInt();
        int y=in.nextInt();
        char array[][]=new char[x][y];
        for(int i=0;i<x;i++){
            String cha=in.next();
            array[i]=cha.toCharArray();
        }

        dfs(0,0,x,y,array);
        System.out.println(display(array));
    }
}

广度优先搜索

详介

http://blog.csdn.net/yake827/article/details/52679104

理解广度优先搜索

http://www.cnblogs.com/baiyanhuang/archive/2011/04/17/1999196.html

BFS 广度优先搜索 解析

http://blog.csdn.net/wr132/article/details/43274397

例题:

poj 4001 抓住那头牛 (广度优先搜索算法)

http://blog.csdn.net/king_way/article/details/33305017

总时间限制:
2000ms
内存限制:
65536kB

描述

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:
1、从X移动到X-1或X+1,每次移动花费一分钟
2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

输入
两个整数,N和K
输出
一个整数,农夫抓到牛所要花费的最小分钟数
样例输入

5 17

样例输出

4

解析:

http://www.xuebuyuan.com/2138923.html

作为一个只知道bfs大概概念的我,即使是再“水”的题我也无所适从啊!
当然,聪明如我,先把代码打出来,一个个断点打过去就知道最简单的bfs的实现情况啦
code:

package Chapter4;

import java.util.LinkedList;
import java.util.Queue;

public class CatchThatCow {
    //定义最大量
    static int MAX=100000;
    //step[n]的值为n处距离起点的步数,如起点n=5,step[5]=0,则5处离起点5的步数为“走0步就到了”
    static int[] step=new int[MAX];
    //是否已被访问过,从逻辑上推理,如果这个点访问过,如果继续访问下去一定没有之前访问过再访问下去的路径短
    static boolean[] visited=new  boolean[MAX];
    //记录步骤的队列,在java中简单队列是linkedList,enqueue()对应add(),dequeue对应poll()
    static Queue<Integer> bfsTree=new LinkedList<>();
    //定义起点N和终点K
    static int N=5;
    static int K=17;
    
    static int bfs(){
        //当前路径的起点
        int head=0;
        //head接下来可以去的方向
        int next=0;
        //N为起点,所以n处已被访问
        visited[N]=true;
        //N离N 0步
        step[N]=0;
        //入队
        bfsTree.add(N);
        //bfsTree不为空时循环
        while(!bfsTree.isEmpty()){
            //得到队列的第一个
            head=bfsTree.peek();
            //出队
            bfsTree.poll();
            //根据题意,有三种走向
            for(int i=0;i<3;i++) {
                if (i == 0) {
                    next = head - 1;
                } else if (i == 1) {
                    next = head + 1;
                } else {
                    next = head * 2;
                }
                //超范围了就不管了
                if (next < 0 || next >= MAX) {
                    continue;
                }
                //被访问了就不管了
                if (!visited[next]) {
                    visited[next] = true;
                    //next就在head的下一步,所以step++
                    step[next] = step[head] + 1;
                    //入队
                    bfsTree.add(next);
                }
                //如果下一步是终点,那就输出终点的步数
                if (next == K) {
                    return step[next];
                }
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        //输出结果
        System.out.println(bfs());
    }
}

我想注释还是比较详细的,应该能入个小门了

这个是我理解的原理图

image.png

记录步骤的例题:

http://blog.csdn.net/llzhh/article/details/51067351

这是只得到最短路径长度的代码

package Chapter4;

import java.util.LinkedList;
import java.util.Queue;
class Point{
    public int row;
    int column;
    boolean visited;
    int step;
    public Point(int x,int y){
        this.row=x;
        this.column=y;
        visited=false;
        step=0;
    }
}
public class Maze {

    static int[][] maze={
            {0, 1, 0, 0, 0},
            {0, 1, 0, 1, 0},
            {0, 0, 0, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 0, 1, 0},
    };
    static int[] xStep={-1,1,0,0};
    static int[] yStep={0,0,-1,1};
    static Queue<Point> bfsTree=new LinkedList<>();
    static void bfs(){
        Point[][] pointList=new Point[5][5];
        for(int i=0;i<5;i++){
            for(int j=0;j<5;j++){
                Point p=new Point(i,j);
                pointList[i][j]=p;
            }
        }
        pointList[0][0].visited=true;
        bfsTree.add(pointList[0][0]);
        while (!bfsTree.isEmpty()){
            Point head=bfsTree.poll();
            for(int i=0;i<4;i++){
                int x=head.row+xStep[i];
                int y=head.column+yStep[i];
                if(x<0 || y<0 || x>4 || y>4 || maze[x][y]==1){
                    continue;
                }
                if(!pointList[x][y].visited){
                    pointList[x][y].visited=true;
                    pointList[x][y].step=pointList[head.row][head.column].step+1;
                    bfsTree.add(pointList[x][y]);
                }
                if(x==4 && y==4){
                    display(pointList[4][4]);
                    return;
                }
            }
        }
    }
    static void display(Point point){
        System.out.println("shortest:"+point.step);
    }
    public static void main(String[] args) {
        bfs();
    }
}

接下来我们优化代码,得到最短路径的步骤

package Chapter4;

import java.util.LinkedList;
import java.util.Queue;
class Point{
    public int row;
    int column;
    boolean visited;
    int step;
    Point lastPoint;
    public Point(int x,int y,Point lastPoint){
        this.row=x;
        this.column=y;
        visited=false;
        step=0;
        this.lastPoint=lastPoint;
    }
}
public class Maze {

    static int[][] maze={
            {0, 1, 0, 0, 0},
            {0, 1, 0, 1, 0},
            {0, 0, 0, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 0, 1, 0},
    };
    static int[] xStep={-1,1,0,0};
    static int[] yStep={0,0,-1,1};
    static Queue<Point> bfsTree=new LinkedList<>();
    static void bfs(){
        Point[][] pointList=new Point[5][5];
        for(int i=0;i<5;i++){
            for(int j=0;j<5;j++){
                Point p=new Point(i,j,null);
                pointList[i][j]=p;
            }
        }
        pointList[0][0].visited=true;
        bfsTree.add(pointList[0][0]);
        while (!bfsTree.isEmpty()){
            Point head=bfsTree.poll();
            for(int i=0;i<4;i++){
                int x=head.row+xStep[i];
                int y=head.column+yStep[i];
                if(x<0 || y<0 || x>4 || y>4 || maze[x][y]==1){
                    continue;
                }
                if(!pointList[x][y].visited){
                    pointList[x][y].visited=true;
                    pointList[x][y].step=pointList[head.row][head.column].step+1;
                    pointList[x][y].lastPoint=pointList[head.row][head.column];
                    bfsTree.add(pointList[x][y]);
                }
                if(x==4 && y==4){
                    display(pointList);
                    return;
                }
            }
        }
    }
    static void display(Point[][] pointList){
        Point lastPoint=pointList[4][4];
        System.out.println("倒序输出:");
        while (lastPoint.lastPoint != null){
            System.out.println(lastPoint.row+","+lastPoint.column);
            lastPoint=lastPoint.lastPoint;
        }
        System.out.println("0,0");
    }
    public static void main(String[] args) {
        bfs();
    }
}

优化的部分就是在类Point中加入了一个指针,指向上一个点,最后输出,此代码粗糙,是倒序的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容