BFS 相关题目

本文介绍了如何利用广度优先搜索(BFS)和剪纸游戏的思路来解决AtCoder竞赛中的ABC339D任务,以及在牛客网小白月赛中的类似问题。代码展示了如何处理边界条件,遍历路径,并通过动态规划找到最少步数到达目标。
摘要由CSDN通过智能技术生成

题目1:
https://atcoder.jp/contests/abc339/tasks/abc339_d

代码:

#include <bits/stdc++.h>
using namespace std;

#define ll long long
// #define int long long
const int N = 66;
const int dx[] = {0, 0, -1, 1};
const int dy[] = {1, -1, 0, 0};

struct node {
    int a, b, c, d;
};
int n;
string s[N];
int dp[N][N][N][N];

bool Bad(int x, int y) {
    return x <= 0 || y <= 0 || x > n || y > n || s[x][y] == '#';
}

int main() {
    cin >> n;
    int sx1 = -1, sy1 = -1, sx2 = -1, sy2 = -1;  // 两个玩家的坐标
    for (int i = 1; i <= n; i++) {
        cin >> s[i];
        s[i] = " " + s[i];  // 方便j从1开始计数
        // 确定P的坐标
        for (int j = 1; j <= n; j++) {
            if (s[i][j] == 'P') {
                if (sx1 == -1) {
                    sx1 = i, sy1 = j;
                } else {
                    sx2 = i, sy2 = j;
                }
            }
        }
    }
    queue<node> q;                 // bfs核心--队列
    q.push({sx1, sy1, sx2, sy2});  // 四个坐标一起遍历
    memset(dp, -1, sizeof dp);     // 表示从个点从初始状态的操作数
    dp[sx1][sy1][sx2][sy2] = 0;    // 初始状态操作数为0
    while (!q.empty()) {
        // 取队首元素
        auto u = q.front();
        q.pop();
        int a = u.a, b = u.b, c = u.c, d = u.d;
        for (int i = 0; i < 4; i++) {  // 四个方向进行宽度优先搜索
            // 两个点都向i方向运动
            int na = a + dx[i], nb = b + dy[i];
            int nc = c + dx[i], nd = d + dy[i];
            // 遇到边界和障碍物
            if (Bad(na, nb)) {
                na = a, nb = b;
            }
            if (Bad(nc, nd)) {
                nc = c, nd = d;
            }
            if (dp[na][nb][nc][nd] == -1) {
                dp[na][nb][nc][nd] = dp[a][b][c][d] + 1;
                q.push({na, nb, nc, nd});  // 放入队列中
            }
        }
    }
    int mn = 2e9;
    for (int a = 1; a <= n; a++) {
        for (int b = 1; b <= n; b++) {
            if (dp[a][b][a][b] != -1) {
                mn = min(mn, dp[a][b][a][b]);
            }
        }
    }
    if (mn == 2e9) {
        cout << -1 << endl;
    } else {
        cout << mn << endl;
    }
    system("pause");
    return 0;
}

题目2:

D-剪纸游戏_牛客小白月赛86 (nowcoder.com)

代码:

#include <bits/stdc++.h>
using namespace std;

#define ll long long
// #define int long long
#define MAX_H 1000
#define MAX_W 1000

int h, w;
char grids[MAX_H][MAX_W];

int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
typedef struct {
    int y;
    int x;
} Pair;

bool check(int y, int x) {
    int minY = y, minX = x;
    int maxY = y, maxX = x;
    int cnt = 1;
    // 用Pair的形式定义一个数组(实现队列)
    Pair deq[MAX_H * MAX_W];
    int front = 0, rear = 0;
    deq[rear++] = (Pair){y, x};
    grids[y][x] = '*'; // 注意这里的操作

    while (front < rear) {
        Pair pos = deq[front++];
        for (int i = 0; i < 4; i++) {
            int ty = pos.y + dirs[i][0];
            int tx = pos.x + dirs[i][1];
            if (ty >= 0 && ty < h && tx >= 0 && tx < w &&
                grids[ty][tx] == '.') {
                // 神之一手
                grids[ty][tx] = '*';
                deq[rear++] = (Pair){ty, tx};
                cnt++;
                // 计算最小点和最大点
                minY = (ty < minY) ? ty : minY;
                minX = (tx < minX) ? tx : minX;
                maxY = (ty > maxY) ? ty : maxY;
                maxX = (tx > maxX) ? tx : maxX;
            }
        }
    }
    return minY == y && minX == x &&
           (maxX - minX + 1) * (maxY - minY + 1) == cnt;
}

int main() {
    cin >> h >> w;
    for (int i = 0; i < h; i++) {
        cin >> grids[i];
    }
    int res = 0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (grids[i][j] == '.') {
                if (check(i, j)) {
                    res++;
                }
            }
        }
    }
    cout << res << endl;
    system("pause");
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值