两次bfs 逃离迷宫

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

给你一个n*m的图,地图上'.'代表可以走的地方,而'#'代表陷阱不能走,
'P'代表人物位置,'K'代表钥匙,'E'代表出口。人物一个,钥匙有多个,
('K'的数量<=50)),出口一个,每个位置可以向(上,下,左,右)四个
方向走一格,花费一个单位时间,现在你需要花费最少的时间拿到钥匙
然后从迷宫的出口出去(若没有钥匙,则不能进入迷宫出口所在的格子)。

输入描述:

第一行一个整数T(T <= 50),代表数据的组数
接下来一行n,m(n<=500,m<=500),代表地图的行和列
接下来n行,每行一个长度为m的字符串,组成一个图。

输出描述:

如果可以出去,输出所花费的最少时间。
如果不能出去,输出一行"No solution"。

示例1

输入

3
5 5
....P
##..E
K#...
##...
.....
5 5
P....
.....
..E..
.....
....K
5 5
P#..E
.#.#.
.#.#.
.#.#.
...#K

输出

No solution
12
No solution

分析

 

第一次错误的代码是先bfs钥匙,找到钥匙再bfs到终点,就是内置bfs,这样子会造成tle

代码

#include<bits/stdc++.h>

using namespace std;

const int N = 600;

bool vis[N][N];
bool vis2[N][N];

char g[N][N];


int dist_key[N][N];

int dist_out[N][N];

typedef pair<int,int> PII;

int t;

int n,m,px,py,ex,ey;

int dist = 0x3f3f3f3f;

int dx[] = {-1,1,0,0},dy[] = {0,0,-1,1};

bool f_key;
bool f_out;

int bfs2(int x,int y)
{
    memset(vis2,false,sizeof vis2);
    memset(dist_out,0x3f3f3f,sizeof dist_out);
    dist_out[x][y] = 0;
    
    queue<PII> q;
    q.push({x,y});
    vis2[x][y] = true;
    
    while(q.size())
    {
        PII cur = q.front();
        q.pop();
        for(int i = 0;i<4;i++)
        {
            int xx = cur.first + dx[i],yy = cur.second + dy[i];
             if(xx>=1 && xx<=n && yy>=1 && yy<=m &&(g[xx][yy] =='.'|| g[xx][yy] == 'E') && !vis2[xx][yy])
             {
                 dist_out[xx][yy] = min(dist_out[xx][yy],dist_out[cur.first][cur.second] +1);
                 vis2[xx][yy] = true;
                 q.push({xx,yy});
             }
        }
    }
    
    
    
    if(dist_out[ex][ey] == 0x3f3f3f3f) return -1;
    else 
        return dist_out[ex][ey];
    
}

int bfs(int x,int y)
{
    memset(vis,false,sizeof vis);
    memset(dist_key,0x3f3f3f,sizeof dist_key);
    dist_key[x][y] = 0;
    
    queue<PII> q;
    q.push({x,y});
    vis[x][y] = true;
    
    while(q.size())
    {
        PII cur = q.front();
        q.pop();
        
        for(int i = 0;i<4;i++)
        {
            int xx = cur.first + dx[i],yy = cur.second + dy[i];
            if(xx>=1 && xx<=n && yy>=1 && yy<=m && (g[xx][yy] =='.'|| g[xx][yy] == 'K') && !vis[xx][yy])
            {
                vis[xx][yy] = true;
                dist_key[xx][yy] = min(dist_key[xx][yy],dist_key[cur.first][cur.second]+1);       
                q.push({xx,yy});
                
                if(g[xx][yy] == 'K')
                {
                    f_key = true;
                    int k = bfs2(xx,yy);
                    if(k != -1)
                    {
                        f_out = true;
                        dist = min(dist,dist_key[xx][yy]+k);
                    }
                }
            }
        }
    }
    
    if(dist == 0x3f3f3f3f)return -1;
    else return dist;
}

int main()
{
    cin>>t;
    
    while(t--)
    {
        dist = 0x3f3f3f3f;
        f_key = f_out = false;
        
        cin>>n>>m;
        
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=m;j++)
            {
                cin>>g[i][j];
                if(g[i][j] == 'P')
                {
                    px = i,py = j;
                }
                if(g[i][j] == 'E')
                {
                    ex = i,ey = j;
                }
            }
        }
        
        int r = bfs(px,py);
        
        if(r == -1)cout<<"No solution"<<endl;
        else
            cout<<r<<endl;
       
    }
    
    return 0;
}















 

正确的思路应该是分两次bfs,第一次从起点记录钥匙的位置和距离,第二次从终点走,如果走到已经记录过的钥匙,算出距离,求最小值即可

ac代码

#include<bits/stdc++.h>
 
using namespace std;
 
const int N = 600;
 
bool vis[N][N];
bool vis2[N][N];
 
char g[N][N];
 
 
int dist_key[N][N];
int dist_out[N][N];
int sum[N][N];
 
typedef pair<int,int> PII;
 
int t;
 
int n,m,px,py,ex,ey;
 
int dist = 0x3f3f3f3f;
 
int dx[] = {-1,1,0,0},dy[] = {0,0,-1,1};
 
 
void bfs(int x,int y)
{
    memset(vis,false,sizeof vis);
    memset(dist_key,0x3f3f3f,sizeof dist_key);
    dist_key[x][y] = 0;
     
    queue<PII> q;
    q.push({x,y});
    vis[x][y] = true;
     
    while(q.size())
    {
        PII cur = q.front();
        q.pop();
         
        for(int i = 0;i<4;i++)
        {
            int xx = cur.first + dx[i],yy = cur.second + dy[i];
            if(xx>=1 && xx<=n && yy>=1 && yy<=m && (g[xx][yy] =='.'|| g[xx][yy] == 'K') && !vis[xx][yy])
            {
                vis[xx][yy] = true;
                dist_key[xx][yy] = min(dist_key[xx][yy],dist_key[cur.first][cur.second]+1);       
                q.push({xx,yy});
                if(g[xx][yy] == 'K')
                {
                    sum[xx][yy]++;
                }
            }
        }
    }
}
 
void bfs2(int x,int y)
{
    memset(vis,false,sizeof vis);
    memset(dist_out,0x3f3f3f,sizeof dist_out);
    dist_out[x][y] = 0;
     
    queue<PII> q;
    q.push({x,y});
    vis[x][y] = true;
     
    while(q.size())
    {
        PII cur = q.front();
        q.pop();
         
        for(int i = 0;i<4;i++)
        {
            int xx = cur.first + dx[i],yy = cur.second + dy[i];
            if(xx>=1 && xx<=n && yy>=1 && yy<=m && (g[xx][yy] =='.'|| g[xx][yy] == 'K') && !vis[xx][yy])
            {
                vis[xx][yy] = true;
                dist_out[xx][yy] = min(dist_out[xx][yy],dist_out[cur.first][cur.second]+1);       
                q.push({xx,yy});
                if(g[xx][yy] == 'K')
                {
                    if(sum[xx][yy])
                    {
                        dist = min(dist,dist_key[xx][yy] + dist_out[xx][yy]);
                    }
                }
            }
        }
    }
}
 
int main()
{
    cin>>t;
     
    while(t--)
    {
        dist = 0x3f3f3f3f;
         
        cin>>n>>m;
         
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=m;j++)
            {
                cin>>g[i][j];
                if(g[i][j] == 'P')
                {
                    px = i,py = j;
                }
                if(g[i][j] == 'E')
                {
                    ex = i,ey = j;
                }
            }
        }
         
        
         
       bfs(px,py);
        bfs2(ex,ey);
         
        if(dist == 0x3f3f3f3f) cout<<"No solution"<<endl;
        else
            cout<<dist<<endl;
        
    }
     
    return 0;
}

 

 

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值