题解 SP13076 【CSLIKAR - Slikar】

题目传送门

算法:超级源点 + 两次 BFS

对于这一类走迷宫的题, BFS 是十分常见的手法。(推荐一道题:UVA589 Pushing Boxes

在本题中,如果水和潘特“同时行动”,并不容易处理。因此可以先对洪水进行 BFS,标记洪水第一次弥漫到的时间,然后再对潘特进行 BFS,如果潘特到达的时间大于等于洪水漫到的时间,那么就不能走。

在做洪水的 BFS 时,由于有多个“出发点”,可以考虑设置超级源点,即建立一个虚拟的“出发点”,对每一个洪水的“出发点”连接一条权值为 0 的边,最后从超级源点开始做 BFS 就行。

不熟超级源点的同学戳这里(引自网络)

code:

#include<bits/stdc++.h>
using namespace std;
const int N=51;
int r,c;
int tw[N][N],tc[N][N];//tw 记洪水漫到的时间,tc记人到的时间 
int g[4][2] {{1,0},{-1,0},{0,1},{0,-1}};//四个方向 
char pc[N][N];
struct point {
    int x,y;
} wat[N*N],d,ci;
bool check_water(int x,int y) {
    if(x<1||x>r||y<1||y>c||tw[x][y]||pc[x][y]=='D'||pc[x][y]=='X')return false;
    //如果超出边界或者遇到障碍和终点,不能漫过去 
    return true;
}
bool check_pante(int x,int y,int t0) {
    if(x<1||x>r||y<1||y>c||tc[x][y]||pc[x][y]=='X')return false;
    //如果超出边界、遇到障碍或者走过,不走 
    if(t0>=tw[x][y]&&tw[x][y])return false;
    //如果走到前(或走到时)洪水已经漫过,那么不能走 
    return true;
}
void bfs_water(int cnt) {//对洪水进行bfs 
    queue<point> q;
    for(int i=1; i<=cnt; i++) {
        q.push(wat[i]);//超级源:直接将所有的出发点放进队列 
        tw[wat[i].x][wat[i].y]=1;
    }
    while(!q.empty()) {
        point f=q.front();
        q.pop();
        for(int i=0; i<4; i++) {
            int x=f.x+g[i][0],y=f.y+g[i][1];
            if(check_water(x,y)) {
                tw[x][y]=tw[f.x][f.y]+1;
                q.push({x,y});
            }
        }
    }
}
void bfs_pante(int x0,int y0) {//对人进行bfs 
    queue<point>q;
    q.push({x0,y0});
    tc[x0][y0]=1;
    while(!q.empty()) {
        point f=q.front();
        q.pop();
        for(int i=0; i<4; i++) {
            int x=f.x+g[i][0],y=f.y+g[i][1],t=tc[f.x][f.y]+1;
            if(check_pante(x,y,t)) {
                tc[x][y]=t;
                if(x==d.x&&y==d.y) {
                    printf("%d",tc[x][y]-1);//由于起点设为 1 表示走过,答案要减 1 
                    exit(0);//得到答案,直接结束程序 
                }
                q.push({x,y});
            }
        }
    }
}
int main() {
    cin>>r>>c;
    int cnt=0;
    for(int i=1; i<=r; i++) {
        for(int j=1; j<=c; j++) {
            cin>>pc[i][j];
            if(pc[i][j]=='D')d= {i,j},tw[i][j]=1e9;//终点,水漫不到,可以直接将水漫到的时间设为极大值 
            if(pc[i][j]=='*')wat[++cnt]= {i,j};//记录所有的洪水出发点 
            if(pc[i][j]=='S')ci= {i,j};
        }
    }
    bfs_water(cnt);
    bfs_pante(ci.x,ci.y);
    printf("KAKTUS");//不行的情况 
    return 0;
}

迷宫题一般难度不大,但比较注重细节,可以有效提升代码功底。

感谢观看

AC

致歉:由于提交的题解多次出现排版上的疏忽,给管理员造成不便,特此致歉。

posted @ 2021-06-23 13:32  Maplisky  阅读(53)  评论(0编辑  收藏  举报