• BFS及其变形


    相较于深度搜索的一条路走到黑,广度搜索如其名是逐层搜索,一次把整一层搜完。我们用一个队列来实现,每次取出队头,对于队头状态的所有分支,把沿着分支所能达到的下一个状态(如果这个状态没被访问过或者可以形成更优的解)插入队尾,直到队列为空。

    复习:#150 骑士游历

    一个比较典型的棋盘问题,题目先规定了大致的方向,否则的话,应该有8个方向进行遍历;

    先规定一个next数组,表示走到下一个点需要的运算;

    用book来表示是否已经走过;

    当第一次走到终点的时候直接输出;

    否则搜索完毕之后输出no solution;

     1 #include <iostream>
     2 using namespace std;
     3 struct queue{
     4     int x;
     5     int y;
     6     int step;
     7 }q[2510];
     8 int next[4][2]={{2,1},{2,-1},{1,2},{1,-2}};
     9 int book[51][51],nx,ny;
    10 int main(){
    11     int head=1,tail=1,k,n,m;
    12     cin>>n>>m;
    13     book[1][1]=1,q[head].x =1;q[head].y=1,q[head].step =0;
    14     tail++;
    15     book[1][1]=0;
    16     k=0;
    17     while(head!=tail){
    18         for(int i=0;i<=3;i++){
    19             nx=q[head].x +next[i][0];
    20             ny=q[head].y +next[i][1];
    21             if(nx<1||nx>n||ny<1||ny>m) continue;
    22             if(book[nx][ny]==0){
    23                book[nx][ny]=1;
    24                q[tail].x =nx;
    25                q[tail].y =ny;
    26                q[tail].step =q[head].step +1;
    27                tail++;
    28             }
    29             if(nx ==n&&ny ==m){
    30                 k=1;
    31                 break;
    32             }
    33         }
    34         if(k==1) break;
    35         head++;
    36     }
    37     if(k==1) cout<<q[tail-1].step;
    38     else cout<<"No solution!";
    39     return 0;
    40 }
    View Code

    给一道例题:矩阵距离(ch2501)

    描述

    给定一个N行M列的01矩阵 A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
    dist(A[i][j],A[k][l])=|i-k|+|j-l|

    输出一个N行M列的整数矩阵B,其中:
    B[i][j]=min(1≤x≤N,1≤y≤M,A[x][y]=1)⁡{dist(A[i][j],A[x][y])}
    即求与每个位置曼哈顿距离最近的1
    N,M≤1000。

    输入格式

    第一行两个整数n,m。

    接下来一个N行M列的01矩阵,数字之间没有空格。

    输出格式

    一个N行M列的矩阵B,相邻两个整数之间用一个空格隔开。

    题目所求的意思就是 :

    离 (i,j) 这个点最近的 “1” 的曼哈顿距离;

    然后输出这个矩阵;

    我们先来思考一个问题:

    给一个地图,全是0、1; 从一个起点出发,1表示不能走,0表示可以走。就可以求得起点到每一个可到达的点 的最小步数。

    这样的问题我们形象的称它为倒水 、

    于是本题便可以看作是一个有着多个起点(start) 的倒水问题;

    在开始搜索前将所有的起点入队,然后用广搜。

    当(x,y)这个节点第一次被访问时,便是离它最近的一个起点搜索到了它,这时候用的步数即为b[x][y];

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 using namespace std;
     7 const int dx[4] = { -1,1,0,0 }, dy[4] = { 0,0,-1,1 };
     8 char s[1020][1020];
     9 int d[1020][1020], n, m;
    10 queue<pair<int, int>> q;
    11 int main()
    12 {
    13     cin >> n >> m;
    14     for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
    15     memset(d, -1, sizeof(d));
    16     for (int i = 1; i <= n; i++)
    17         for (int j = 1; j <= m; j++)
    18             if (s[i][j] == '1') q.push(make_pair(i, j)), d[i][j] = 0;
    19     while (q.size()) {
    20         pair<int, int> now = q.front();
    21         q.pop();
    22         for (int k = 0; k < 4; k++) {
    23             pair<int, int> next(now.first + dx[k], now.second + dy[k]);
    24             if (next.first<1 || next.second<1 || next.first>n || next.second>m) continue;
    25             if (d[next.first][next.second] == -1) {
    26                 d[next.first][next.second] = d[now.first][now.second] + 1;
    27                 q.push(next);
    28             }
    29         }
    30     }
    31     for (int i = 1; i <= n; i++) {
    32         for (int j = 1; j <= m; j++) printf("%d ", d[i][j]);
    33         puts("");
    34     }
    35 }
    View Code

    BFS 的变形

    例题:电路维修(ch2601)

    这道题我们输入存储数据的时候有一个小技巧。

    将每个电路图中的格点当作无向图中的节点。

    对于两个节点x,y;

    如果他们是在同一个格子的两个角上,就将它连一条边,如果x到y有一根导线,就将x到y的边权设为0

    反之 如果是垂直的话,就设为1(这表示需要旋转一次才能够连上)

    然后我们只需要求出从左上角到右下角的最短距离;

    进行bfs的时候,我们将边权为0的边延伸出来的节点从队头入队;

    为1的边延伸出来的节点从队尾入队;

    因为如果这样做,我们就能保证每当一个节点第一次出队时,这时的总权值是最优解;

    这种bfs变形叫做 双端队列

     1 #include <deque>
     2 #include <vector>
     3 #include <cstring>
     4 #include <iostream>
     5 using namespace std;
     6 const int N = 506;
     7 int r, c, d[N][N];
     8 bool v[N][N];
     9 char s[N][N];
    10 vector<pair<pair<int, int>, int> > p[N][N];
    11 deque<pair<int, int> > q;
    12 
    13 void add(int x1, int y1, int x2, int y2, int z) {
    14     p[x1][y1].push_back(make_pair(make_pair(x2, y2), z));
    15 }
    16 
    17 void dlwx() {
    18     cin >> r >> c;
    19     for (int i = 1; i <= r; i++) cin >> (s[i] + 1);
    20     if ((r & 1) != (c & 1)) cout << "NO SOLUTION" << endl;
    21     for (int i = 0; i <= r; i++)
    22         for (int j = 0; j <= c; j++)
    23             p[i][j].clear();
    24     for (int i = 1; i <= r; i++)
    25         for (int j = 1; j <= c; j++)
    26             if (s[i][j] == '/') {
    27                 add(i - 1, j - 1, i, j, 1);
    28                 add(i, j, i - 1, j - 1, 1);
    29                 add(i, j - 1, i - 1, j, 0);
    30                 add(i - 1, j, i, j - 1, 0);
    31             } else {
    32                 add(i - 1, j - 1, i, j, 0);
    33                 add(i, j, i - 1, j - 1, 0);
    34                 add(i, j - 1, i - 1, j, 1);
    35                 add(i - 1, j, i, j - 1, 1);
    36             }
    37     memset(d, 0x3f, sizeof(d));
    38     d[0][0] = 0;
    39     memset(v, 0, sizeof(v));
    40     q.clear();
    41     q.push_back(make_pair(0, 0));
    42     while (q.size()) {
    43         int x = q.front().first, y = q.front().second;
    44         q.pop_front();
    45         v[x][y] = 1;
    46         if (x == r && y == c) {
    47             cout << d[r][c] << endl;
    48             return;
    49         }
    50         for (unsigned int i = 0; i < p[x][y].size(); i++) {
    51             int nx = p[x][y][i].first.first;
    52             int ny = p[x][y][i].first.second;
    53             int nz = p[x][y][i].second;
    54             if (v[nx][ny]) continue;
    55             if (nz) {
    56                 if (d[nx][ny] > d[x][y] + 1) {
    57                     d[nx][ny] = d[x][y] + 1;
    58                     q.push_back(make_pair(nx, ny));
    59                 }
    60             } else {
    61                 if (d[nx][ny] > d[x][y]) {
    62                     q.push_front(make_pair(nx, ny));
    63                     d[nx][ny] = d[x][y];
    64                 }
    65             }
    66         }
    67     }
    68 }
    69 
    70 int main() {
    71     int t;
    72     cin >> t;
    73     while (t--) dlwx();
    74     return 0;
    75 }
    View Code

    优先队列 bfs 

    其实双端队列算是优先队列dfs的一个特殊情况,因为权值只有0、1;

    对于更加普适性的情况,我们可以用到优先队列;

    这时优先队列是一个二叉堆,每次取出当前代价最小的节点进行扩展;

    说白了:在最短路中就是堆优化的dijstra算法

     

    双向的bfs

     就是有两个节点同时bfs,当一个点是第一次被搜索到既能被一个起点到达,也能被另一个点到达,则当前轮数就是最短的两点会和时间;

  • 相关阅读:
    iOS开发笔记 — Text、UI交互细节、两个动画效果等
    iOS数据库存储数组或字典等数据
    NSMutableAttributedString使用
    进军OC之必备C语言知识点
    iOS开发之c语言基础 扩展知识点 及 企业面试题
    iOS开发之c语言基础Lesson-11 函数指针 上课笔记 与 试题练习
    iOS开发之c语言基础Lesson-10 动态内存管理 上课笔记 与 试题练习
    指针与数组的区别和联系
    iOS开发之c语言基础Lesson-09 高级指针 上课笔记 与 试题练习
    iOS开发之c语言基础Lesson-08 指针 上课笔记 与 试题练习
  • 原文地址:https://www.cnblogs.com/lirh04/p/12878152.html
Copyright © 2020-2023  润新知