P1128-绝地求生
题目描述:
小H所在的地方有毒气扩散,现在他必须赶去安全区。
他所在的地方可以用一个N∗M的地图表示。
.表示空地,人和毒气都可以经过
*表示毒气的地方(可能有多个地方有毒气)
X表示障碍物,两者均不能经过
S表示小H初始的位置
D表示安全区(注意:安全区不会被毒气入侵)
小H每分钟可以往上下左右四个相邻位置移动,同时毒气也会从已有毒气的区域扩散到相邻的区域。
小H想知道到达安全区的最少时间,如果不能到达安全区,他将呼叫他的队友“HELP”。
输入格式:
输入第一行有两个数字分别为N和M
接下来输入N行,每行M个字符,表示小H所在区域的地图
输入保证S,D只出现一次。
1≤N,M≤50
输出格式:
如果可以到达安全区,输出一个整数,表示到达安全区的最少时间。
如果到达不了输出"HELP"(不含引号)
输入样例:
3 6
D...*.
.X.X..
....S.
输出格式:
6
思路:题目中说明毒圈位置不止一个,所以本题明显是一道多源bfs的题,故记录时间,在每分钟小H可以到达的地点入队之后,然后将这一分钟有那些毒圈可以向四周扩散,并将扩散的点入队(并且将入对的点时间+1),按照这个思路就可以解决本题。
菜鸟代码:
#include<bits/stdc++.h>
using namespace std;
const int N=55;
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
struct bs
{
int x,y,s; //(x,y)是位置,s代表时间
}t;
queue<bs>q,p; //定义两个队列,q用于存放小H路径,p用于存放毒圈扩散路径
int n,m,ans;
char ma[N][N]; //存放地图
bool vis[N][N],flag; //vis作为标记数组
void bfss(int x);
void bfs() //广搜判断小H能否到达安全区
{
while(!q.empty())
{
t=q.front();
q.pop();
if(ma[t.x][t.y]=='D') //成功到达安全区
{
flag=true; //将标记改为true,证明可以成功到达安全区
ans=t.s;
return;
}
for(int i=0;i<4;i++) //对四个方向进行遍历
{
int tx=t.x+dx[i];
int ty=t.y+dy[i];
if(tx<0||ty<0||tx>=n||ty>=m||vis[tx][ty]) //判断小H能否过去
continue;
if(ma[tx][ty]=='.'||ma[tx][ty]=='D')
{
vis[tx][ty]=true;
q.push({tx,ty,t.s+1}); //将下一步位置入队,时间+1分钟
}
}
bfss(t.s); //毒圈进行扩散,注意只能是本分钟毒圈才可以扩散
}
}
void bfss(int x) //对每分钟毒圈位置向四周扩散的点进行广搜入队
{
while(!p.empty())
{
bs t1=p.front();
if(t1.s>x) return; //不要忽略,每分钟可以扩散的毒圈入队,由本分钟毒圈入队的点在本分钟不能扩散,需要到下一分钟才可以扩散
p.pop();
for(int i=0;i<4;i++)
{
int tx=t1.x+dx[i];
int ty=t1.y+dy[i];
if(tx<0||ty<0||tx>=n||ty>=m) //判断是否在地图以内
continue;
if(ma[tx][ty]=='.'&&!vis[tx][ty]) //
{
vis[tx][ty]=true;
ma[tx][ty]='*'; //将扩散的地点标记为毒圈
p.push({tx,ty,t1.s+1}); //入队,下一次毒圈扩散的时间在本分钟上加1
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
scanf("%s",&ma[i]);
for(int j=0;j<m;j++)
{
if(ma[i][j]=='S') //将小H初始点入队
q.push({i,j,0});
if(ma[i][j]=='*') //将初始地图中的毒圈点全部入队便于后面扩散
p.push({i,j,0});
}
}
bfs();
if(flag) cout<<ans<<endl;
else cout<<"HELP"<<endl;
return 0;
}