3 条题解

  • 1
    @ 2026-3-6 16:57:59

    由于火可以蔓延到四周,人也可以前往四周(除了#的地方)所以我们可以在结构体中多加入状态p,表示当前扩散的是人还是火。注意到: 如果一个格子已经着火,或者在乔进入该格子的时刻恰好着火,则该格子对乔来说是危险的,乔不能进入该格子。 那么我们可以先扩散火 再走人 否则会因为特判问题头痛(其实是我不会写)详细见代码

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int r,c,sx,sy;//行列,开始的坐标
    char a[1010][1010];//地图
    int dx[]={-1,1,0,0};
    int dy[]={0,0,-1,1};//偏移
    struct grid{
        int x,y,p;//p=0时表示是人 p=1时表示火
    };
    int dis[1010][1010];//距离
    vector<grid>f;
    void bfs(int x,int y,int p){
        queue<grid>q;
        for(int i=0;i<f.size();i++){//先着火 把火全部入队
            int e=f[i].x,r=f[i].y,c=f[i].p;
            q.push({e,r,c});
        }
        q.push({x,y,p});
        dis[x][y]=0;//人再入队
        while(!q.empty()){
            int tx=q.front().x,ty=q.front().y,tp=q.front().p;
            q.pop();//拿到队首并出队
            if(tp==0){//人跑出去了
                if(tx==1||tx==r||ty==1||ty==c){
                    cout<<dis[tx][ty]+1;
                    return ;
                }
            }
            for(int i=0;i<4;i++){
                int nx=tx+dx[i],ny=ty+dy[i],np=tp;
            if(nx>=1&&nx<=r&&ny>=1&&ny<=c&&a[nx][ny]!='#'){//不越界的同时不是障碍
                if(np==0){//人
                if(a[nx][ny]=='.'&&dis[nx][ny]==-1){//空地+没走过 不能走火
                dis[nx][ny]=dis[tx][ty]+1;//更新距离
                q.push({nx,ny,0});
                }
                }
                else if(np==1){//火
                if(a[nx][ny]!='F'){//注意下一个不能是火 不然会导致重复状态
                a[nx][ny]='F';
                q.push({nx,ny,1});
                }
                }
                }
            }
        }
        cout<<"IMPOSSIBLE";
    }
    signed main(){
        ios::sync_with_stdio(0);
        cin.tie(0);
        cin>>r>>c;
        for(int i=1;i<=r;i++){
            for(int j=1;j<=c;j++){
                cin>>a[i][j];
                dis[i][j]=-1;//初始化
                if(a[i][j]=='J'){
                    sx=i,sy=j;
                }
                if(a[i][j]=='F'){
                  f.push_back({i,j,1});//把火全部放进数组中 在bfs开始时先入队
                }
            }
        }
        if(sx==1||sx==r||sy==1||sy==c){//特判一下开局就可以跑出去
            cout<<1;
            return 0;
        }
        bfs(sx,sy,0);
    }
    
    • 0
      @ 2026-5-15 22:26:57

      先用bfs跑一遍火和人走到每一格的最短时间 最后再找人能走到而且火没跑到的最短边缘 AC代码:

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N=1010;
      struct node {
          int x;int y;
      };
      char mp[N][N];
      int f[N][N];
      int q[N][N];
      int xlj[4]={1,-1,0,0};
      int ylj[4]={0,0,1,-1};
      int n;int m;
      void bfs(int st[N][N],queue<node>&qqq) {
          while (!qqq.empty()) {
              node t=qqq.front();qqq.pop();
              for (int i=0;i<4;i++) {
                  int x=t.x+xlj[i];
                  int y=t.y+ylj[i];
                  if (mp[x][y]=='#')continue;
                  if (st[x][y]!=-1)continue;
                  if (x<1||x>n||y<1||y>m)continue;
                  qqq.push({x,y});
                  st[x][y]=st[t.x][t.y]+1;
              }
          }
      }
      int main() {
          ios::sync_with_stdio(false);
          cin.tie(nullptr);
          cout.tie(nullptr);
          cin>>n>>m;
          queue<node>fq;
          queue<node>qq;
          for (int i=1;i<=n;i++) {
              string s;cin>>s;
              for (int j=1;j<=m;j++) {
                  mp[i][j]=s[j-1];
                  f[i][j]=-1;
                  q[i][j]=-1;
                  if (mp[i][j]=='F') {
                      fq.push({i,j});
                      f[i][j]=0;
                  }
                  if (mp[i][j]=='J') {
                      qq.push({i,j});
                      q[i][j]=0;
                  }
              }
          }
          bfs(q,qq);
          bfs(f,fq);
          for (int i=1;i<=n;i++)qq.push({i,1});
          for (int i=1;i<=m;i++)qq.push({1,i});
          for (int i=1;i<=n;i++)qq.push({i,m});
          for (int i=1;i<=m;i++)qq.push({n,i});
          int ans=INT_MAX;
          while (!qq.empty()) {
              node t=qq.front();qq.pop();
              int x=t.x;int y=t.y;
              if (q[x][y]!=-1&&(q[x][y]<f[x][y]||f[x][y]==-1)) {
                  ans=min(q[x][y],ans);
              }
          }
          if (ans==INT_MAX) cout<<"IMPOSSIBLE";
          else cout<<ans+1;
          return 0;
      }
      
      
      • 0
        @ 2026-4-7 20:56:16

        是个好模板题 不难但是ex

        #include<bits/stdc++.h>
        using namespace std;
        #define int long long
        /* n*m J是人的位置:.是路 #是墙 F是火(可能有多个) 火不断向四周蔓延 J逃跑到墙外就可以算成功了 
          问:j逃出去花费的最少时间 如果出不去返回IMPOSSIBLE 、
          //okok 来看看本题:本题其实是一个模板:多源BFS记时
          1:我们可以利用F 求出F【】【】 即火到各个地方的最短时间
          2:对于人我们要求 a[][]即走到每部的时间 
        */
        #define PII pair<int,int> 
        const int N=1200;
        char g[N][N];
        int a[N][N];
        int f[N][N];
        int n,m;
        int ans=1e9;
        int dx[]={1,-1,0,0};
        int dy[]={0,0,-1,1};
        bool check(int x,int y)
        {
        	if(x<0||x>n-1||y<0||y>m-1) return 0;
        	return 1;
        }
        void bfs()
        {
          queue<PII> q;
          for(int i=0;i<n;i++)//先初始化 放入所有单原 
           for(int j=0;j<m;j++)
           {
           	 if(g[i][j]=='F')
           	 {
           	 	q.push({i,j});
        		f[i][j]=0;	 
        	 }
           }
          while(q.size())
          {
            auto t=q.front();
            q.pop();
        	int xx=t.first;
        	int yy=t.second;
        	for(int i=0;i<4;i++)
        	{
        	  int nx=xx+dx[i];
        	  int ny=yy+dy[i];
        	  if(check(nx,ny)&&f[nx][ny]==0)
        	   {
        	     f[nx][ny]=f[xx][yy]+1;
        		 q.push({nx,ny});	
        	   }	
        	}	
          }
          return;	
        }
        void bfs2(int x,int y,int s[][N])//这俩代码相似复制修 
        { 
          queue<PII> q;
          q.push({x,y});
          a[x][y]=0; 
          while(q.size())
          { 
            auto t=q.front();
            q.pop();
        	int xx=t.first;
        	int yy=t.second;
        	//先判定终点
        	if(!check(xx,yy)) 
        	{ ans=s[xx][yy];
        	  break;//第一个出去的就行 
            }
        	for(int i=0;i<4;i++)
        	{
        	  int nx=xx+dx[i];
        	  int ny=yy+dy[i];
        	 if(s[nx][ny]==0 && (f[nx][ny]==0 || s[xx][yy]+1 < f[nx][ny]))
        	 //1:要看能不能走出去不要check 2走到下一步火还没来3不重复不撞墙 
        	   {
        	     s[nx][ny]=s[xx][yy]+1;
        		 q.push({nx,ny});	
        	   }	
        	}	
          }
          return;		
        }
        signed main()
        { std::ios::sync_with_stdio(0);
          cin.tie(0),cout.tie(0);
          cin>>n>>m;
          int x1,y1;//j的位置 
          for(int i=0;i<n;i++)
           for(int j=0;j<m;j++)
           {
             cin>>g[i][j];
        	 if(g[i][j]=='#') a[i][j]=-1,f[i][j]=-1; 
        	 if(g[i][j]=='J') x1=i,y1=j;	
           }	
         //1得到火焰数组 注意只要是火焰就先加入q
          bfs(); 
         //ok再来看J	 
          bfs2(x1,y1,a);
          if(ans==1e9) cout<<"IMPOSSIBLE"<<"\n";
          else cout<<ans<<"\n";  
        	return 0;
        }
        
        • 1

        信息

        ID
        524
        时间
        1000ms
        内存
        256MiB
        难度
        普及−
        标签
        递交数
        173
        已通过
        40
        上传者