zoukankan      html  css  js  c++  java
  • 一些搜索总结

    双向BFS

    我们在BFS时,要从起点,搜遍整颗搜索树,然后找到终点,整个过程大概是一个如下的结构

    我比较懒,所以图非常简陋。

    最上面的节点表示起点,最下面的点表示终点。

    我们正常的BFS是从起点一路向下搜到终点,这样要扩展不少的状态,耗费不少的时间。

    这样我们想我们其实可以从起点和终点同时开始搜,起点和终点同时向外扩展一步,当两个搜索路径交会时,结束搜索。

    这样我们可以省去一半的时间。

    我们用两个队列分别表示起点的扩展和终点的扩展

    例题:

    常见的迷宫问题,0表示有障碍,1表示无障碍,假设没有无法走到的情况,求最少需要多少步

    非常显然的BFS

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 3030;
     4 struct node {
     5     int x, y;
     6 }q1[maxn], q2[maxn];
     7 //int stx, sty, edx, edy;
     8 int a[maxn][maxn];
     9 int n, m;
    10 int    tail1 = 0, head1 = 1, tail2 = 0, head2 = 1;
    11 //int dx[9] = {-1, -1, 1, 1, -2, -2, 2, 2};
    12 //int dy[9] = {2, -2, 2, -2, -1, 1, -1, 1};
    13 //int vis[maxn][maxn];
    14 int dx[5] = {-1, 0, 1, 0}, dy[5] = {0, -1, 0, 1};
    15 int st[maxn][maxn], ed[maxn][maxn];
    16 int stept[maxn][maxn], stepe[maxn][maxn];
    17 bool flag = 0;
    18 int ans = 0;
    19 
    20 inline int read() {
    21     int x = 0, y = 1;
    22     char ch = getchar();
    23     while(!isdigit(ch)) {
    24         if(ch == '-') y = -1;
    25         ch = getchar();
    26     }
    27     while(isdigit(ch)) {
    28         x = (x << 1) + (x << 3) + ch - '0';
    29         ch = getchar();
    30     }
    31     return x * y;
    32 }
    33 
    34 int main() {
    35     memset(st, 0, sizeof(st));
    36     memset(ed, 0, sizeof(ed));
    37     memset(a, -1, sizeof(a)); 
    38     n = read(), m = read();
    39     for(int i = 1; i <= n; ++i)
    40         for(int j = 1; j <= m;++j)
    41             a[i][j] = read();
    42     q1[++tail1].x = 1, q1[tail1].y = 1;
    43     q2[++tail2].x = n, q2[tail2].y = m;
    44     for(head1 = 1, head2 = 1; head1 <= tail1 || head2 <= tail2; head1++, head2++) {
    45         for(int i = 0; i < 4; ++i) {
    46             int xx = q1[head1].x + dx[i];
    47             int yy = q1[head1].y + dy[i];
    48             if(a[xx][yy] == -1) continue;
    49             if(!st[xx][yy] && a[xx][yy]) {
    50                 stept[xx][yy] = stept[q1[head1].x][q1[head1].y] + 1;
    51                 if(ed[xx][yy]) {
    52                     flag = 1;
    53                     ans = stept[xx][yy] + stepe[xx][yy];
    54                     break;
    55                 }
    56                 st[xx][yy] = 1;
    57                 q1[++tail1].x = xx;
    58                 q1[tail1].y = yy;
    59             }
    60         }
    61         if(flag == 1) break;
    62         for(int i = 0; i < 4; ++i) {
    63             int xx = q2[head2].x + dx[i];
    64             int yy = q2[head2].y + dy[i];
    65             if(a[xx][yy] == -1) continue;
    66             if(!ed[xx][yy] && a[xx][yy]) {
    67                 stepe[xx][yy] = stepe[q2[head2].x][q2[head2].y] + 1;
    68                 if(st[xx][yy]) {
    69                     flag = 1;
    70                     ans = stepe[xx][yy] + stept[xx][yy];
    71                     break;
    72                 }
    73                 ed[xx][yy] = 1;
    74                 q2[++tail2].x = xx;
    75                 q2[tail2].y = yy;
    76             }
    77         }
    78         if(flag == 1) break;
    79     }
    80     cout << ans << '
    ';
    81     return 0;
    82 }
    View Code

    迭代加深搜索

    在一些需要搜索的情况下,使用DFS会因为搜索树的深度太深,加上结果比较靠后,而导致耗费巨大的时间,而如果使用BFS,则会因为要存储大量状态而耗费大量的空间

    这个时候我们可以使用迭代加深搜索。

    简而言之就是我们人为规定一个搜索深度,每次到限定的搜索深度时停止。

    比如说第一次我们规定搜索深度为1,我们搜索一层,结束

    第二次我们规定搜索深度为2,我们搜索两层,结束

    .......

    这样我们会发现我们绝对会出现大量的重复计算,但是这对于我们直接进行DFS在搜索树上跑所需要的时间来说,是少得多的,这样这个算法就显得优秀了

    例题1:

    这题我们可以发现直接DFS我们似乎无法下手,我们可以脑洞一下,构造出一颗搜索树(当然我在口胡)

    我们可以发现从第一个分叉向下扩展,可能会扩展的非常深都没有找到答案。用BFS我们固然可写,但是会耗费不小的空间。

    这样我们就可以迭代加深搜索。

    需要注意的是黑白棋是交替下的,而且题面并没有明确说是黑棋先下还是白棋先下

    我们需要对黑先和白先分别进行计算

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 6;
     4 const int deep = 1000000000;
     5 int ox1, oy1, ox2, oy2;//分别记录两个空白地带的坐标
     6 char ch[maxn]; 
     7 char a[maxn][maxn];
     8 bool flag = 0;
     9 int dx[5] = {-1, 0, 1, 0}, dy[5] = {0, 1, 0, -1};
    10 int ans = 0;
    11 
    12 inline bool check() {
    13     for(int i = 1; i <= 4; ++i) {
    14         if(a[1][i] == a[2][i] && a[1][i] == a[3][i] && a[1][i] == a[4][i]) return 1;//判断是否存在竖着的四子连棋 
    15         if(a[i][1] == a[i][2] && a[i][1] == a[i][3] && a[i][1] == a[i][4]) return 1;//判断是否存在横着的四子连棋 
    16     }
    17     if(a[1][1] == a[2][2] && a[1][1] == a[3][3] && a[1][1] == a[4][4]) return 1;//判断是否存在由左上到右下角的四子连棋 
    18     if(a[1][4] == a[2][3] && a[1][4] == a[3][2] && a[1][4] == a[4][1]) return 1;//判断是否存在由右上到左下角的四子连棋 
    19     return 0;
    20 }
    21 
    22 inline bool able(int x, int y, int dad) {
    23 return x >= 1 && x <= 4 && y >= 1 && y <= 4 && a[x][y] != dad;}
    24 
    25 bool deepdfs(int x1, int y1, int x2, int y2, char pre, int begin) {
    26     if(begin == ans) {
    27         if(check()) return 1;
    28         else return 0;
    29     }
    30     for(int i = 0; i < 4; ++i) {
    31         int xx = x1 + dx[i];
    32         int yy = y1 + dy[i];
    33         if(able(xx, yy, pre)) {
    34             swap(a[x1][y1], a[xx][yy]);
    35             if(deepdfs(xx, yy, x2, y2, (pre == 'W' ? 'B' : 'W'), begin + 1)) return 1;
    36             swap(a[x1][y1], a[xx][yy]);
    37         }
    38         xx = x2 + dx[i];
    39         yy = y2 + dy[i];  
    40         if(able(xx, yy, pre)) {
    41             swap(a[x2][y2], a[xx][yy]);
    42             if(deepdfs(x1, y1, xx, yy, (pre == 'W' ? 'B' : 'W'), begin + 1)) return 1;
    43             swap(a[x2][y2], a[xx][yy]);
    44         }
    45     }
    46     return 0;
    47 }
    48 
    49 int main() {
    50     //memset(a, -1, sizeof(a));
    51     for(int i = 1; i <= 4; ++i) {
    52         cin >> ch + 1;
    53         for(int j = 1; j <= 4; ++j) {
    54             if(ch[j] == 'B') a[i][j] = 'B';
    55             else if(ch[j] == 'W') a[i][j] = 'W';
    56             if(ch[j] == 'O') {
    57                 a[i][j] = 'O';
    58                 if(!flag) {ox1 = i, oy1 = j;flag = 1;}
    59                 else if(flag) ox2 = i, oy2 = j;
    60             }
    61         }
    62     }
    63     /*for(uint i = 1; i <= 4; ++i) {
    64         for(uint j = 1; j <= 4; ++j)
    65             cout << a[i][j] << ' ';
    66         cout << '
    ';
    67     }*/
    68     for(ans = 1; ans <= deep; ++ans) {//迭代加深搜索枚举搜索限定深度 
    69         if(deepdfs(ox1, oy1, ox2, oy2, 'B', 0))
    70             break;
    71         if(deepdfs(ox1, oy1, ox2, oy2, 'W', 0))
    72             break;
    73     }
    74     cout << ans << '
    ';
    75     return 0;
    76 }
    View Code
  • 相关阅读:
    c语言练习24——数列求和
    Excel 常用属性的一小部分
    常见问题一之拼接表格 js传递参数变量 Json接收值
    关于下拉列表HtmlDownlistFor的使用
    Quay 基础版安装和部署
    Prometheus使用blackbox_exporter监控端口及网站状态(七)
    在CentOS 8上安装PostgreSQL 13 | RHEL 8
    nfs配置以及No route to host解决
    LNMP分离安装
    Linux配置和管理设备映射多路径multipath
  • 原文地址:https://www.cnblogs.com/ywjblog/p/9264925.html
Copyright © 2011-2022 走看看