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;

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)的主要内容,如果未能解决你的问题,请参考以下文章

BFS简单迷宫

BFS简单题套路_Codevs 1215 迷宫

迷宫的最短路径(简单BFS)

ACM/ICPC 之 BFS-简单障碍迷宫问题(POJ2935)

蓝桥杯BFS从此搞懂搜索题的套路! | 入门必看

通过迷宫问题简单学习DFS和BFS算法