10.起火迷宫(简单BFS 多源BFS)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10.起火迷宫(简单BFS 多源BFS)相关的知识,希望对你有一定的参考价值。
起火迷宫
↑ 题目链接
题目
一个迷宫可以看作一个 \\(R\\) 行 \\(C\\) 列的方格矩阵。
其中一些方格是空地,用 .
表示,其他方格是障碍,用 #
表示。
开始时,乔位于一块空地之中。
迷宫中一些空地已经起火了,幸运的是火还没有蔓延至乔所在的位置。
为了避免被火烧伤,乔需要尽快逃离迷宫。
已知,乔每单位时间只能沿上下左右四个方向前进一格距离,并且在前进过程中,他不能进入障碍方格。
火每单位时间都会蔓延至其上下左右四个方向的相邻空地,但是火也会被障碍阻挡。
如果一个方格已经起火或者会在乔进入方格的那一时刻恰好起火,则该方格很危险,乔不能进入。
当乔进入到任意一个位于边界的空地方格时,他都可以再花费一单位时间,直接逃离迷宫。
请问,乔想要逃离迷宫,最少需要花费的时间。
输入格式
第一行包含整数 \\(T\\),表示共有 \\(T\\) 组测试数据。
每组数据第一行包含两个整数 \\(R,C\\)
接下来 \\(R\\) 行,包含一个 \\(R×C\\) 的字符矩阵。
矩阵中只包含以下四种字符:
#
表示障碍方格。
.
表示空地方格。
J
表示乔所在的空地方格,最多只有一个。
F
表示已经起火的空地方格。
输出格式
每组数据输出一行结果,一个整数表示逃离迷宫所需花费的最少时间,如果无法逃离迷宫,则输出 IMPOSSIBLE
。
数据范围
\\(1≤T≤10,1≤R,C≤1000\\)
输入样例:
2
4 4
####
#JF#
#..#
#..#
3 3
###
#J.
#.F
输出样例:
3
IMPOSSIBLE
思路
两次 \\(BFS\\) 搜索,只要到达这个格子的时间严格小于这个格子被火覆盖的时间,就能走到这个格子,特判开始在边界的情况
代码
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N=1010;
typedef pair<int,int>PII;
char g[N][N];
bool st[N][N];
int df[N][N],dj[N][N];
int n,m;
int jx,jy;
int dx[]=-1,0,1,0,dy[]=0,1,0,-1;
vector<PII>fire;
//求出所有格子被火覆盖的最短时间(多源bfs, 有多个火种)
void bfs_f()
memset(df,-1,sizeof df);
queue<PII>q;
for(auto t:fire)
q.push(t.x,t.y);
df[t.x][t.y]=0;
while(q.size())
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=m||g[a][b]==\'#\'||df[a][b]!=-1)continue;
df[a][b]=df[t.x][t.y]+1;
q.push(a,b);
//再从起点开始bfs, 只要到达这个格子的时间严格小于这个格子被火覆盖的时间,就能走到这个格子
int bfs_j()
memset(dj,-1,sizeof dj);
queue<PII>q;
q.push(jx,jy);
dj[jx][jy]=0;
if(jx==0||jx==n-1||jx==0||jx==m-1)return 1;//一开始在边界
while(q.size())
auto t=q.front();
q.pop();
for(int i=0;i<4;i++)
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=m||g[a][b]==\'#\'||dj[a][b]!=-1||g[a][b]==\'F\')continue;
if(df[a][b]!=-1&&dj[t.x][t.y]+1>=df[a][b])continue;
dj[a][b]=dj[t.x][t.y]+1;
if(a==0||a==n-1||b==0||b==m-1)return dj[a][b]+1;
q.push(a,b);
return -1;
int main()
int T;
cin>>T;
while(T--)
fire.clear();
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>g[i][j];
if(g[i][j]==\'J\')jx=i,jy=j;
if(g[i][j]==\'F\')fire.push_back(i,j);
bfs_f();
int t=bfs_j();
if(t==-1)puts("IMPOSSIBLE");
else cout<<t<<endl;
return 0;
本文来自博客园,作者:风雨zzm,转载请注明原文链接:https://www.cnblogs.com/zzmxj/p/17368263.html
CF 986A Fair——多源bfs
题目:http://codeforces.com/contest/986/problem/A
如果从每个村庄开始bfs找货物,会超时。
发现k较小。那就从货物开始bfs,给村庄赋上dis[ 该货物 ]。
但这样还是n^2。考虑有相同货物的村庄,其实可以一起bfs。就是多源bfs。这样就是n*k的了。
多源bfs就是把一些起始点的dis全赋了初值0,然后都放进队列里,之后正常bfs。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5,K=105; int n,m,k,s,head[N],xnt,dis[N][K],a[N],q[K][N],h,t[K]; struct Ed{ int next,to; Ed(int n=0,int t=0):next(n),to(t) {} }ed[N<<1]; void add(int x,int y) { ed[++xnt]=Ed(head[x],y);head[x]=xnt; ed[++xnt]=Ed(head[y],x);head[y]=xnt; } int main() { scanf("%d%d%d%d",&n,&m,&k,&s); memset(dis,0x3f,sizeof dis); for(int i=1;i<=n;i++) { scanf("%d",&a[i]);dis[i][a[i]]=0; q[a[i]][++t[a[i]]]=i; } int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y);add(x,y); } for(int i=1;i<=k;i++) { h=1; while(h<=t[i]) { int k=q[i][h++]; for(int j=head[k],v;j;j=ed[j].next) if(dis[v=ed[j].to][i]>dis[k][i]+1) { dis[v][i]=dis[k][i]+1;q[i][++t[i]]=v; } } } for(int i=1;i<=n;i++) { int ans=0;sort(dis[i]+1,dis[i]+k+1); for(int j=1;j<=s;j++)ans+=dis[i][j]; printf("%d ",ans); } return 0; }
以上是关于10.起火迷宫(简单BFS 多源BFS)的主要内容,如果未能解决你的问题,请参考以下文章