第4章 万能的搜索

简介: 第4章 万能的搜索

第4章 万能的搜索

第1节 不撞南墙不回头–深度优先搜索

3.4的全排列问题。

考虑这样解决:如果有k个数要排列,就会排出k位数。

把k位当成k个盒子,k个数当成k张扑克牌,排列的过程就是依次往盒子里放扑克牌。(高中时的排列组合好像经常会这么做)

这种放扑克牌的过程,可以使用深度优先搜索。

深度优先的基本模型:

void dfs(int step)
{
    判断边界
  尝试每一种可能 for()
  {
  继续下一步dfs(step+1)
  }
  返回
}
//n个数的全排列,n范围是1-9
package ch4;

import java.util.Scanner;

public class DFSTest {
  public int[] a =new int[10];//盒子
  public int[] book=new int[10];//标记扑克牌是否在手上,0代表在
  public int n;
  void dfs(int step) {
        //判断边界
    if(step==this.n+1) {
      for(int i=1;i<=n;i++) {
        System.out.print(a[i]); 
      }
      System.out.println();
      return ;
    }
        //尝试每一种可能
    for(int i=1;i<=n;i++) {
      if(book[i]==0) { //牌在手上,放入盒子中
        a[step]=i;
        book[i]=1;
        dfs(step+1);//放完第step个盒子,继续放下一个
        
        book[i]=0;//收回刚刚放的扑克牌,用来下次尝试
      }
    }
    return;
  }
  public static void main(String[] args) {
    DFSTest t = new DFSTest();
    Scanner sc = new Scanner(System.in);
    t.n = sc.nextInt();
    t.dfs(1);
    
  }
}

第2节 解救小哈

迷宫里找到小哈

//迷宫两点最近路径,原题只给出最近路径的值,没给出路径。
//在min=setp处(26行),可以同时记录最短路径
package ch4;

import java.util.Scanner;

public class DFSTest3 {
  int p,q;
  int n,m;
  int[][] a    = new int[51][51];//迷宫
  int[][] book = new int[51][51];//路径
  int min = 99999;
  int[][] map   = new int[51][51];
  int[][]minmap = new int[51][51];
  
  void dfs(int x,int y,int step) {
    //方向,右下左上
    int[][] next= {{0,1},
        {1,0},
        {0,-1},
        {-1,0}};
    int tx,ty,k;
    if(x==p&&y==q) {
      if(step<min) {
        min=step;
        //记录当前路径
        for(int i=1;i<=n;i++) {
          for(int j=1;j<=m;j++) {
            minmap[i][j] = book[i][j];
          }
        }
      }
      return;
    }
    //尝试每一种走法
    for(k=0;k<=3;k++) {
      tx = x+next[k][0];
      ty = y+next[k][1];
      //越界
      if(tx<1||tx>n||ty<1||ty>m) {
        continue;
      }
      //点不在障碍物上且 没有走过
      if(a[tx][ty]==0&&book[tx][ty]==0) {
        book[tx][ty]=1;
        
        dfs(tx,ty,step+1);
        book[tx][ty]=0;
        
      }
    }
    return;
  }
  
  public static void main(String[] args) {
    DFSTest3 t = new DFSTest3();
    Scanner sc = new Scanner(System.in);
    t.n = sc.nextInt();
    t.m = sc.nextInt();
    for(int i=1;i<=t.n;i++) {
      for(int j=1;j<=t.m;j++) {
        t.a[i][j]=sc.nextInt();
      }
    }
    int startx =sc.nextInt();
    int starty= sc.nextInt();
    t.p = sc.nextInt();
    t.q = sc.nextInt();
    t.book[startx][starty]=1;
    t.dfs(startx,starty,0);
    
    System.out.println(t.min);
    for(int i=1;i<=t.n;i++) {
      for(int j=1;j<=t.m;j++) {
        System.out.print(t.minmap[i][j]+" ");
      }
      System.out.println();
    }
    
  }
}

第3节 层层递进–广度优先算法

BFS(breadth first search)

和第2节的深度优先搜索不同,这里使用广度优先不是一直往下找直到找到路为止,而是“一层一层”地寻找,第一次把一步能走到的点都加入队列,第二步利用第一步的点,把两步能走到的点都加入队列,直到小哈被找到就停止扩展。

package ch4;

import java.util.Scanner;

public class BFSTest1 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    node[] que = new node[2501];
    for(int i=0;i<que.length;i++) {
      que[i] = new node();
    }
    
    int [][]a = new int[51][51];
    int [][]book = new int[51][51];
    //方向,右下左上
    int[][] next= {{0,1},
        {1,0},
        {0,-1},
        {-1,0}};
    int head,tail;
    int n = sc.nextInt();
    int m = sc.nextInt();
    for(int i=1;i<=n;i++) {
      for(int j=1;j<=m;j++) {
        a[i][j] = sc.nextInt();
      }
    }
    int startx = sc.nextInt();
    int starty = sc.nextInt();
    int p = sc.nextInt();
    int q = sc.nextInt();
    head =1;
    tail =1;
    //队列插入入口坐标
    que[tail].x=startx;
    que[tail].y=starty;
    que[tail].f = 0;
    que[tail].step = 0;
    tail++;
    book[startx][starty]=1;
    int flag =0;//是否到达目标点,0表示没有到达。
    //队列不为空(还有点可以扩展)时循环
    while(head<tail) {
      //尝试4种方向
      for(int k=0;k<=3;k++) {
        int tx = que[head].x+next[k][0];
        int ty = que[head].y+next[k][1];
        //判断越界
        if(tx<1||tx>n||ty<1||ty>m) {
          continue;
        }
        //判断障碍物或是否在路径
        if(a[tx][ty]==0&&book[tx][ty]==0) {
          book[tx][ty]=1;
          que[tail].x=tx;
          que[tail].y =ty;
          que[tail].f =head;
          que[tail].step=que[head].step+1;
          tail++;
        }
        //找到目标,停止
        if(tx==p&&ty==q) {
          flag =1;
          break;
        }
      }
      if(flag==1) {
        break;
      }
      head++; //当一个扩展点结束后,head++才能对后面的点进行扩展
    }
    System.out.println(que[tail-1].step);
  }
}

class node{
  int x;
  int y;
  int f;  //父亲在队列中的编号
  int step;
}

第4节 再解炸弹人

第3章第2节中的炸弹人问题,求在哪个位置放炸弹消灭敌人最多,求出来的地点可能是炸弹人走不到的,利用本章的搜索可以先找出可以到达的点,再枚举。

第5节 宝岛探险

求解从某个点出发,能到达的全部地点。

和迷宫基本一样。

着色法,只需要在走的过程中加入染色过程a[x][y]=color

找到地图上所有的独立小岛:只需要对每一个大于0(没染色的陆地)的点进行一次深度优先搜索。

测试数据,答案为4
10 10
1 2 1 0 0 0 0 0 2 3
3 0 2 0 1 2 1 0 1 2
4 0 1 0 1 2 3 2 0 1
3 2 0 0 0 1 2 4 0 0
0 0 0 0 0 0 1 5 3 0
0 1 2 1 0 1 5 4 3 0
0 1 2 3 1 3 6 2 1 0
0 0 3 4 8 9 7 5 0 0
0 0 0 3 7 8 6 0 1 2
0 0 0 0 0 0 0 0 1 0
package ch4;

import java.util.Scanner;

public class DFSTest5 {
  int sum;
  int n,m;
  int[][] a    = new int[51][51];//迷宫
  int[][] book = new int[51][51];//路径
  
  
  void dfs(int x,int y,int color) {
    //方向,右下左上
    int[][] next= {{0,1},
        {1,0},
        {0,-1},
        {-1,0}};
    int tx,ty,k;
    a[x][y] = color; //染色
    //尝试每一种走法
    for(k=0;k<=3;k++) {
      tx = x+next[k][0];
      ty = y+next[k][1];
      //越界
      if(tx<1||tx>n||ty<1||ty>m) {
        continue;
      }
      //点在陆地上且 没有走过
      if(a[tx][ty]>0 &&book[tx][ty]==0) {
        sum++;
        book[tx][ty]=1;
        dfs(tx,ty,color);
        
      }
    }
    return;
  }
  
  public static void main(String[] args) {
    DFSTest5 t = new DFSTest5();
    Scanner sc = new Scanner(System.in);
    t.n = sc.nextInt();
    t.m = sc.nextInt();
    for(int i=1;i<=t.n;i++) {
      for(int j=1;j<=t.m;j++) {
        t.a[i][j]=sc.nextInt();
      }
    }
    int num = 0;//染色的颜色
    for(int i=1;i<=t.n;i++) {
      for(int j=1;j<=t.m;j++) {
        if(t.a[i][j]>0) {
          num--;
          t.book[i][j]=1;
          t.dfs(i, j, num);
        }
      }
    }
    
    for(int i=1;i<=t.n;i++) {
      for(int j=1;j<=t.m;j++) {
        System.out.printf("%3d",t.a[i][j]);
      }
      System.out.println();
    }
    System.out.println("共有"+(-num)+"个小岛");
  }
}

第6节 水管工游戏

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cg7LbWF6-1589449662208)(C:\Users\LF\AppData\Roaming\Typora\typora-user-images\1588902125296.png)]

可以使用深度优先搜索解决,

过程类似走迷宫,但是当前一步要根据上一步的管子方向确定,而且相应的下一步的位置也被当前一步的管子方向决定。

package ch4;

import java.util.Scanner;

public class DFSTest6 {
  class node
  {
    int x;
    int y;
    node(int x,int y){
      this.x=x;
      this.y=y;
    }
    
  }
  int n,m;
  int flag;
  int top=0;
  int [][]book = new int[51][51];
  int [][]a = new int[51][51];
  node[] s = new node[100];
  

  void dfs(int x,int y,int front) {
    if(x==n&&y==m+1) {
      flag = 1;
      for(int i=1;i<=top;i++) {
        System.out.printf("(%d,%d) ",s[i].x,s[i].y);
      }
      return;
    }
    //判断越界
    if(x<1 || x>n || y<1 || y>m) {
      return ;
    }
    //判断已经使用过
    if(book[x][y]==1) {
      return;
    }
    book[x][y]=1;
    top++;
    s[top] = new node(x,y);
    
    //当前水管是直管 5/6
    if(a[x][y]>=5&&a[x][y]<=6) {
      if(front==1) { //进水口在左边
        dfs(x,y+1,1);
      }
      if(front==2) { //进水口在上边
        dfs(x+1,y,2);
      }
      if(front==3) {//进水口在右边
        dfs(x,y-1,3);
      }
      if(front==4) {//进水口在下边
        dfs(x-1,y,4);
      }
    }
    
    //水管是弯管
    if(a[x][y]>=1&&a[x][y]<=4) {
      if(front==1) { //进水口在左边
        dfs(x+1,y,2);
        dfs(x-1,y,4);
      }
      if(front==2) { //进水口在上边
        dfs(x,y+1,2);
        dfs(x,y-1,3);
      }
      if(front==3) {//进水口在右边
        dfs(x-1,y,4);
        dfs(x+1,y,2);
      }
      if(front==4) {//进水口在下边
        dfs(x,y+1,1);
        dfs(x,y-1,3);
      }
    }
    book[x][y]=0;
    top--;
    return;
    
      
    
  }
  
  public static void main(String[] args) {
    DFSTest6 t = new DFSTest6();
    Scanner sc = new Scanner(System.in);
    t.n=sc.nextInt();
    t.m=sc.nextInt();
    for(int i=1;i<=t.n;i++) {
      for(int j=1;j<=t.m;j++) {
        t.a[i][j]=sc.nextInt();
      }
    }
    t.dfs(1,1,1);
    if(t.flag==0) {
      System.out.println("impossible");
    }
    
  }
}


) {//进水口在下边

dfs(x,y+1,1);

dfs(x,y-1,3);

}

}

book[x][y]=0;

top–;

return;

}

public static void main(String[] args) {
  DFSTest6 t = new DFSTest6();
  Scanner sc = new Scanner(System.in);
  t.n=sc.nextInt();
  t.m=sc.nextInt();
  for(int i=1;i<=t.n;i++) {
    for(int j=1;j<=t.m;j++) {
      t.a[i][j]=sc.nextInt();
    }
  }
  t.dfs(1,1,1);
  if(t.flag==0) {
    System.out.println("impossible");
  }
  
}

}


相关文章
|
6月前
|
存储 搜索推荐 安全
Onlyfans如何使用搜索功能?Onlyfans如何搜索博主?如何在OnlyFans搜索HongkongDoll
本文是一份全面的指南,旨在帮助读者了解如何在OnlyFans平台上有效使用搜索功能,尤其是如何找到特定的博主,比如HongkongDoll。我们深入探讨了OnlyFans的搜索机制,包括其对用户隐私的重视以及因此带来的搜索限制。文章详细介绍了三种主要的搜索方法:使用OnlyFans的官方搜索服务、通过社交媒体链接进行跳转、以及利用第三方搜索引擎如OnlySearch。
|
6月前
|
JSON JavaScript 数据格式
超有意思的模糊搜索
超有意思的模糊搜索
|
移动开发 算法
秒懂算法 | A*搜索
本篇内容包括了A*搜索算法的原理精解以及2个例题。
525 1
秒懂算法 | A*搜索
|
小程序 数据库
小程序搜索功能,云开发搜索,小程序云开发模糊搜索,同时搜索多个字段
小程序搜索功能,云开发搜索,小程序云开发模糊搜索,同时搜索多个字段
276 0
|
存储 并行计算 算法
秒懂算法 | 搜索基础
本篇介绍了BFS和DFS的概念、性质、模板代码。
157 0
秒懂算法 | 搜索基础
【Axure教程】通讯录搜索案例(字母定位+模糊搜索
【Axure教程】通讯录搜索案例(字母定位+模糊搜索
【Axure教程】通讯录搜索案例(字母定位+模糊搜索
|
前端开发 小程序 关系型数据库
小程序中实现搜索功能
小程序中实现搜索功能
小程序中实现搜索功能
|
小程序 容器
小程序实现搜索功能续
小程序实现搜索功能续
小程序实现搜索功能续
|
Python
百度搜索的高级用法
百度搜索的高级用法
2982 0
百度搜索的高级用法