C++U5-05-广度优先搜索2

发布时间 2023-11-14 11:52:42作者: 小虾同学

广搜逻辑

 

 广搜代码核心思路

 广搜伪代码

前面讲解的广度优先搜索案例都类似迷宫类的问题,但有些非迷宫类问题也可以使用广搜的思路解决

[【广搜2】填涂颜色]

【算法分析】
可以在外面增加一圈 0,然后从 (0,0) 位置开始广搜所有为 0 的位置,没有被搜索到且为 0 的位置就应该变为 2。

【参考代码】
#include<bits/stdc++.h>
using namespace std;

int a[39][39];
bool vis[39][39];
struct node {
    int x, y;
}l,r;
int n;
int dir[4][2] = { -1,0,0,1,1,0,0,-1 };
void bfs(int x, int y) {
    queue<node> q;
    q.push({ x,y });
    vis[x][y] = 1;
    while (q.size()) {
        r = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            l.x = r.x + dir[i][0], l.y = r.y + dir[i][1];
            if (l.x >= 0 && l.x <= n + 1 && l.y >= 0 && l.y <= n + 1 && !vis[l.x][l.y] && a[l.x][l.y] == 0) {
                vis[l.x][l.y] = 1;
                q.push(l);
            }
        }
    }
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
        }
    }
    bfs(0, 0);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (a[i][j] == 0 && !vis[i][j]) {
                cout << 2 << " ";
            }
            else cout << a[i][j] << " ";
        }
        cout << '\n';
    }
    return 0;
}
View Code

[【广搜2】抓住那头牛]

 

【算法分析】
由于位置的个数很少且要求最小步数,可以考虑从 n 位置开始广搜,同时用一个数组 d,d 
i
​
  表示从 n 位置到 i 位置需要的步数,最后输出 d 
k
​
  即可。

【参考代码】
#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 9;
int d[maxn];
int main() {
    int n, k;
    cin >> n >> k;
    memset(d, -1, sizeof(d));
    d[n] = 0;
    queue<int> q;
    q.push(n);
    while (q.size()) {
        int r = q.front();
        q.pop();
        if (r >= 1 && d[r - 1] == -1) {
            d[r - 1] = d[r] + 1;
            q.push(r - 1);
        }
        if (r < 1e5 && d[r + 1] == -1) {
            d[r + 1] = d[r] + 1;
            q.push(r + 1);
        }
        if (2 * r <= 1e5 && d[2 * r] == -1) {
            d[2 * r] = d[r] + 1;
            q.push(2 * r);
        }
    }
    cout << d[k];
    return 0;
}
View Code

 

[【广搜2】奇怪的电梯]

【算法分析】
由于位置的个数很少且要求最小步数,可以考虑从 A 位置开始广搜,同时用一个数组 d,di 表示从 A 位置到 i 位置需要的步数,最后输出 d B
​
  即可。

【参考代码】
#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e2 + 9;
int d[maxn], k[maxn];
int main() {
    int N, A, B;
    cin >> N >> A >> B;
    for (int i = 1; i <= N; i++) cin >> k[i];
    memset(d, -1, sizeof(d));
    d[A] = 0;
    queue<int> q;
    q.push(A);
    while (q.size()) {
        int r = q.front();
        q.pop();
        if (r + k[r] <= N && d[r + k[r]] == -1) {
            d[r + k[r]] = d[r] + 1;
            q.push(r + k[r]);
        }
        if (r - k[r] >= 1 && d[r - k[r]] == -1) {
            d[r - k[r]] = d[r] + 1;
            q.push(r - k[r]);
        }
    }
    cout << d[B];
    return 0;
}
View Code

 

[【广搜2】倒水问题]

 

【算法分析】
可以从 (0,0) 状态开始广搜,在广搜的每一步记录 x,y,step,s,分别表示第一个杯子装的水,第二个杯子装的水,达到这个状态需要的步数,达到这个状态的操作步骤。

【参考代码】
#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e2 + 9;
bool vis[maxn][maxn];
struct node {
    int x, y, step;
    string s;
}l, r;
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    vis[0][0] = 1;
    queue<node> q;
    q.push({ 0,0,0,"" });
    while (q.size()) {
        r = q.front();
        q.pop();
        if (r.x == k || r.y == k) {
            cout << r.step << '\n' << r.s;
            return 0;
        }
        l.x = n, l.y = r.y, l.step = r.step + 1, l.s = r.s + "FILL(1)\n";
        if (!vis[l.x][l.y]) {
            vis[l.x][l.y] = 1;
            q.push(l);
        }
        l.x = r.x, l.y = m, l.step = r.step + 1, l.s = r.s + "FILL(2)\n";
        if (!vis[l.x][l.y]) {
            vis[l.x][l.y] = 1;
            q.push(l);
        }
        l.x = 0, l.y = r.y, l.step = r.step + 1, l.s = r.s + "DROP(1)\n";
        if (!vis[l.x][l.y]) {
            vis[l.x][l.y] = 1;
            q.push(l);
        }
        l.x = r.x, l.y = 0, l.step = r.step + 1, l.s = r.s + "DROP(2)\n";
        if (!vis[l.x][l.y]) {
            vis[l.x][l.y] = 1;
            q.push(l);
        }
        l.x = max(0, r.x + r.y - m), l.y = min(m, r.x + r.y), l.step = r.step + 1, l.s = r.s + "POUR(1,2)\n";
        if (!vis[l.x][l.y]) {
            vis[l.x][l.y] = 1;
            q.push(l);
        }
        l.x = min(n, r.x + r.y), l.y = max(0, r.x + r.y - n), l.step = r.step + 1, l.s = r.s + "POUR(2,1)\n";
        if (!vis[l.x][l.y]) {
            vis[l.x][l.y] = 1;
            q.push(l);
        }
    }
    cout << "impossible";
    return 0;
}
View Code