0
点赞
收藏
分享

微信扫一扫

第一届程序设计竞赛题解(I题)

彩虹_bd07 2022-04-24 阅读 96
c++算法

I.从你的全世界路过

题目描述:

输入描述:

输出描述:

示例:

思路:
双重最短路问题,可以使用两个 BFS 来求解,利用队列实现,分别求出毒气到达某点的最短时间和陈末到达某点的最短时间。特别要注意,毒气不止一个地方有,每次遍历都需要查找毒气的位置;而陈末的位置只有一个,找到后即可标记下来。
每次比较时间,若毒气的时间小于陈末到达的时间,则陈末可以走,直到出口。

AC代码如下:

#include <bits/stdc++.h>
#define PII pair<int, int>
#define ll long long
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e3 + 5;

int n, m;
char mp[N][N];//地图数组
int a[N][N];//毒气到达该点的时间
int b[N][N];//陈末到达该点的时间
int sx, sy;//陈末的起点位置
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};//方向数组
int ans;//陈末走出迷宫时间

struct node{
    int x;
    int y;
    int t;//时间
};

queue<PII> ta;//存放毒气的队列
queue<node> tb;//存在陈末的队列

//这里我将两个 bfs 放在一块写了
void bfs()
{
    while (!ta.empty()){
        //申请名为 u 的保存两个整数的pair容器
        PII u = ta.front();//取出队首元素放入pair容器中
        ta.pop();//删除队首元素

        for (int i = 0; i < 4; i++){
            //下一个点的坐标
            int xx = u.first + dx[i], yy = u.second + dy[i];

            //判断边界和墙壁
            if (xx < 1 || yy < 1 || xx > n || yy > m || mp[xx][yy] == '#')
                continue;

            //不更新已经走过的位置
            if (a[xx][yy] <= a[u.first][u.second] + 1)
                continue;

            //拓展后,符合条件的点放入队尾
            ta.push({xx, yy});

            //毒气到达该点的最短时间
            a[xx][yy] = min(a[xx][yy], a[u.first][u.second] + 1);
        }
    }

    //陈末的队列放入陈末的起点,时间初始化为0
    tb.push({sx, sy, 0});
    b[sx][sy] = 0;

    ans = -1;
    while (!tb.empty()){
        //取出队首元素放入结构体中
        node v = tb.front();
        //用完删除队首元素
        tb.pop();

        //如果走到了边界
        if (v.x == 1 || v.y == 1 || v.x == n || v.y == m ){
            //且下一步时,人到达的时间小于毒气到达的时间
            if (a[v.x][v.y] >= v.t + 1){
                //将时间加一
                ans = v.t + 1;
                break;
            }
        }

        //遍历下一个点
        for (int i = 0; i < 4; i++){
            int xx = v.x + dx[i], yy = v.y + dy[i];

            if (xx < 1 || yy < 1 || xx > n || yy > m)
                continue;

            if (b[xx][yy] <= v.t + 1)
                continue;

            //如果没有毒气,且人到达的时间小于毒气到达的时间,放入队尾
            if (mp[xx][yy] == '.' && v.t + 1 <= a[xx][yy]){
                tb.push({xx, yy, v.t + 1});

                //时间加一
                b[xx][yy] = v.t + 1;
            }
        }

    }

}

int main()
{
    scanf("%d %d\n", &n, &m);

    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++){
            cin >> mp[i][j];

            //将时间初始化尽量大
            a[i][j] = b[i][j] = INF;

            //找到陈末的起点
            if (mp[i][j] == 'C'){
                sx = i;
                sy = j;
            }

            //找到毒气的位置,放入队列中,标记
            if (mp[i][j] == '*'){
                ta.push({i, j});

                //初始化时间为0
                a[i][j] = 0;
            }
        }
    }

    //调用BFS遍历
    bfs();

    if (ans == -1)
        puts("NO");
    else
        printf("%d\n", ans);

    return 0;
}


举报

相关推荐

0 条评论