带门和钥匙的迷宫

迷宫

https://ac.nowcoder.com/acm/problem/15136

迷宫

题意:

有一个二维迷宫,需要从S点走到E点,每一步之能选择上下左右四个方向前进一格。W代表墙壁,D代表一扇门,需持有钥匙才能通过,K代表钥匙,经过该点钥匙就会自动进入你的口袋,'.'代表是空的,可以走。

问你从起点到终点最少需要几步?

思路:

因为问的是最短路的长度,所以是bfs题

但是这个题介入了钥匙和门这俩恶心的玩意就比较坑!

你不可能通过计算一次bfs就得到答案,因为bfs时每个点只能走一次,用完这个点就扔掉了,不会走回头路,这就会导致一种情况:如样例一

4 12
WWWWWWWWWWWW
WE.W.S..W.KW
W..D..W....W
WWWWWWWWWWWW

第三个就踩到门D了,这个时候你没有钥匙,就会进不去,最后就不能到终点。而这个地方的正解是你先去K处拿到钥匙,再去开门到终点,你会发现会重复走,所以就不是一个bfs能解决的了的事!

我们知道要想到达终点分两种情况,一是不进门去走,看看能不能走到终点,另一种是走门再到终点。

而走门又分为两种情况,一是钥匙会在路上捡到,不用刻意去捡,另一种是得先多跑几步找钥匙,再去开门。总的来说,走门得分两步,先bfs从起点到钥匙处,再bfs从钥匙到门,这样得到的肯定是最小步数。

所以,综上所述,解决这个问题可以分两种情况

  • 将门的位置当成墙,再用bfs去找
  • 先来一步从起点到钥匙的bfs,再来一步从钥匙到门到bfs,再来一步门到终点的bfs,最后三步相加

假设我们bfs没找到最短路时返回的是无穷大,那么如果情况1返回无穷大并且情况二中至少有一个出现无穷大,就说明到不了终点,返回-1

剩下的情况就输出情况一和情况二的最小值

好看一点的AC码

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '\n'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int h, w, x1, yy1, ans, key,xk, yk ,xd, yd;
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
bool vis[505][505];
char tr[505][505];
struct ran{
    int x, y, step;
};
queue<ran>q;
ran over[5];//用来记录点的位置
bool judge(int x, int y){
    if(x > h || x < 1 || y > w || y < 1)return false;
    else if(vis[x][y])return false;
    else if(tr[x][y] == 'W' || tr[x][y] == 'D')return false;
    else return true;
}

int bfs(int xx, int yy){
    ran now, next;
    now.x = xx;now.y = yy;now.step = 0;
    q.push(now);
    vis[xx][yy] = 1;
    while (!q.empty()) {
        now = q.front();q.pop();
//一定要把结束的情况放在外面判断鸭,我之前做了一个判能否走出迷宫的题把这个放在for外面wa了,放里面ac了,所以我写的时候就放里面了,结果wa了,呜呜,写了好长时间呢,后来换了个方法写(也就是这个代码),发现和第一遍一样还是每个步数有的差1有的不差1 ,就发现原来是这个地方出了问题!淦
        if(now.x == x1 && now.y == yy1){
            return now.step;
        }
        for(int i = 0; i < 4; ++i){
            next.x = now.x + dx[i];next.y = now.y +  dy[i];
            if(!judge(next.x, next.y))continue;

            //cout<<now.x<<' '<<now.y<<" -> "<<next.x<<' '<<next.y<<endl;
            vis[next.x][next.y] = 1;
            next.step = now.step + 1;
            q.push(next);
        }
    }
    return inf;
}

void init(){//初始化
    memset(vis, 0, sizeof(vis));
    while (!q.empty()) {
        q.pop();
    }
}

int main(){
    cin>>h>>w;
    for(int i = 1; i <= h; ++i)
    for(int j = 1; j <= w; ++j){
        scanf(" %c",&tr[i][j]);
        if(tr[i][j] == 'S'){//起点
            over[1].x = i;over[1].y = j;
        }
        if(tr[i][j] == 'K'){//钥匙
            over[2].x = i;over[2].y = j;
        }
        if(tr[i][j] == 'D'){//门
            over[3].x = i;over[3].y = j;
        }
        if(tr[i][j] == 'E'){//终点
            over[4].x = i;over[4].y = j;
        }
    }
    init();//从起点到终点
    x1 = over[4].x;yy1 = over[4].y;
    int a = bfs(over[1].x, over[1].y);
    init();//从起点到钥匙
    x1 = over[2].x;yy1 = over[2].y;
    int b = bfs(over[1].x, over[1].y);
    init();//从钥匙到门
    x1 = over[3].x;yy1 = over[3].y;
    tr[over[3].x][over[3].y] = '.';//注意要及时把门给拆了!
    int c = bfs(over[2].x, over[2].y);
    init();//从门到终点
    x1 = over[4].x; yy1 = over[4].y;
    int d = bfs(over[3].x, over[3].y);
    if(a == inf && (b == inf || c == inf || d == inf))
        cout<<-1<<endl;
    else cout<<min(a, b + c + d)<<endl;
    return 0;
}
/*
 5 5
 WWWWW
 WS.KW
 WW.WW
 WD.EW
 WWWWW
 */

在贴一份我第一遍写的奇丑无比的代码(╥﹏╥)

虽然丑了点,但是在我顿悟后改了一下,也ac了W(''0'')W

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '\n'
#define mod 1e9+7;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);

inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int h, w, x1, yy1, ans, key,xk, yk ,xd, yd;
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
bool vis[505][505];
char tr[505][505];
struct ran{
    int x, y, step;
};
queue<ran>q;

bool judge(int x, int y){
    if(x > h || x < 1 || y > w || y < 1)return false;
    else if(vis[x][y])return false;
    else if(tr[x][y] == 'W')return false;
    //else if(tr[x][y] == 'D' && key == 0)return false;
    else return true;
}

int bfs1(){//不走门直接走
    ran now, next;
    now.x = x1;now.y = yy1;now.step = 0;
    vis[x1][yy1] = 1;
    q.push(now);
    while (!q.empty()) {
        now = q.front();q.pop();
        if(tr[now.x][now.y] == 'E'){
            ans = now.step;
            return ans;
            //cout<<"到此为止!\n";
        }
        for(int i = 0; i < 4; ++i){
            next.x = now.x + dx[i];next.y = now.y + dy[i];
            if(!judge(next.x, next.y))continue;
            if(tr[next.x][next.y] == 'D')continue;
            //if(tr[next.x][next.y] == 'K')key = 1;

            //cout<<now.x<<' '<<now.y<<" -> "<<next.x<<' '<<next.y<<endl;
            vis[next.x][next.y] = 1;
            next.step = now.step + 1;
            q.push(next);
        }
    }
    return inf;
}

int bfs2(){//从起点去拿钥匙的距离
    while (!q.empty()) {
        q.pop();
    }
    memset(vis, 0, sizeof(vis));
    ran now, next;
    now.x = x1; now.y = yy1; now.step = 0;
    vis[x1][yy1] = 1;
    q.push(now);
    while (!q.empty()) {
        now = q.front();q.pop();
        if(tr[now.x][now.y] == 'K'){
            ans = now.step;
            return ans;
        }
        for(int i = 0; i < 4; ++i){
            next.x = now.x + dx[i];
            next.y = now.y + dy[i];
            if(!judge(next.x, next.y))continue;
            if(tr[next.x][next.y] == 'D')continue;
           // if(tr[next.x][next.y] == 'K')key = 1;

            next.step = now.step + 1;
            vis[next.x][next.y] = 1;
            q.push(next);

        }
    }
    return inf;
}

int bfs3(){//从钥匙到门
    while (!q.empty()) {
        q.pop();
    }
    memset(vis, 0, sizeof(vis));
    ran now, next;
    now.x = xk; now.y = yk; now.step = 0;
    vis[xk][yk] = 1;
    q.push(now);
    while (!q.empty()) {
        now = q.front();q.pop();
        if(tr[now.x][now.y] == 'D'){
            ans = now.step;
            //cout<<"到此为止!\n";
            return ans;
        }
        for(int i = 0; i < 4; ++i){
            next.x = now.x + dx[i];
            next.y = now.y + dy[i];
            if(!judge(next.x, next.y))continue;
            //if(tr[next.x][next.y] == 'D')continue;
           // if(tr[next.x][next.y] == 'K')key = 1;

            //cout<<now.x<<' '<<now.y<<" -> "<<next.x<<' '<<next.y<<endl;
            next.step = now.step + 1;
            vis[next.x][next.y] = 1;
            q.push(next);

        }
    }
    return inf;
}

int bfs4(){//从门到终点
    while (!q.empty()) {
        q.pop();
    }
    memset(vis, 0, sizeof(vis));
    ran now, next;
    now.x = xd; now.y = yd; now.step = 0;
    vis[xd][yd] = 1;
    q.push(now);
    while (!q.empty()) {
        now = q.front();q.pop();
        if(tr[now.x][now.y] == 'E'){
            ans = now.step;
            return ans;
        }
        for(int i = 0; i < 4; ++i){
            next.x = now.x + dx[i];
            next.y = now.y + dy[i];
            if(!judge(next.x, next.y))continue;
            //if(tr[next.x][next.y] == 'D')continue;
           // if(tr[next.x][next.y] == 'K')key = 1;


            next.step = now.step + 1;
            vis[next.x][next.y] = 1;
            q.push(next);

        }
    }
    return inf;
}


int main(){
    cin>>h>>w;
    for(int i = 1; i <= h; ++i)
    for(int j = 1; j <= w; ++j){
        scanf(" %c",&tr[i][j]);
        if(tr[i][j] == 'S'){
            x1 = i;yy1 = j;
            tr[i][j] = '.';
        }
        if(tr[i][j] == 'K'){
            xk = i;yk = j;
        }
        if(tr[i][j] == 'D'){
            xd = i;yd = j;
        }
    }
    //bfs3();
    int a = bfs1();
    int b = bfs2();
    int c = bfs3();
    int d = bfs4();
    //cout<<a<<' '<<b<<' '<<c<<' '<<d<<endl;
    if(a == inf && (b == inf || c == inf || d == inf))
        cout<<-1<<endl;
    else
        cout<<min(a,b + c + d)<<endl;

    return 0;
}
/*
 5 5
 WWWWW
 WS.KW
 WW.WW
 WD.EW
 WWWWW
 */
全部评论

相关推荐

最近群里有很多同学找我看简历,问问题,主要就是集中在明年三月份的暑期,我暑期还能进大厂嘛?我接下来该怎么做?对于我来说,我对于双非找实习的一个暴论就是title永远大于业务,你在大厂随随便便做点慢SQL治理加个索引,可能就能影响几千人,在小厂你从零到一搭建的系统可能只有几十个人在使用,量级是不一样的。对双非来说,最难的就是约面,怎么才能被大厂约面试?首先这需要一点运气,另外你也需要好的实习带给你的背书。有很多双非的同学在一些外包小厂待了四五个月,这样的产出有什么用呢?工厂的可视化大屏业务很广泛?产出无疑是重要的,但是得当你的实习公司到了一定的档次之后,比如你想走后端,那么中厂后端和大厂测开的选择,你可以选择中厂后端(注意,这里的中厂也得是一些人都知道的,比如哈啰,得物,b站之类,不是说人数超过500就叫中厂),只有这个时候你再去好好关注你的产出,要不就无脑大厂就完了。很多双非同学的误区就在这里,找到一份实习之后,就认为自己达到了阶段性的任务,根本不再投递简历,也不再提升自己,玩了几个月之后,美其名曰沉淀产出,真正的好产出能有多少呢?而实际上双非同学的第一份实习大部分都是工厂外包和政府外包!根本无产出可写😡😡😡!到了最后才发现晚了,所以对双非同学来说,不要放过任何一个从小到中,从中到大的机会,你得先有好的平台与title之后再考虑你的产出!因为那样你才将将能过了HR初筛!我认识一个双非同学,从浪潮到海康,每一段都呆不久,因为他在不断的投递和提升自己,最后去了美团,这才是双非应该做的,而我相信大部分的双非同学,在找到浪潮的那一刻就再也不会看八股,写算法,也不会打开ssob了,这才是你跟别人的差距。
迷茫的大四🐶:我也这样认为,title永远第一,只有名气大,才有人愿意了解你的简历
双非本科求职如何逆袭
点赞 评论 收藏
分享
评论
2
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务