题解 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;
}
迷宫题一般难度不大,但比较注重细节,可以有效提升代码功底。
感谢观看
致歉:由于提交的题解多次出现排版上的疏忽,给管理员造成不便,特此致歉。
本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/14922342.html