迷宫问题 (POJ - 3984 ,BFS + 路径输出)

一.题目链接:

POJ-3984

二.题目大意:

给出一个迷宫,输出路径.

三.分析:

初学 bfs 的小伙伴在入坑 bfs 后,终于学会了判断迷宫问题是否能够到达终点。

那么, 现在又迎来了一个新的问题 —— 若迷宫的解唯一, 那么怎样输出迷宫路径呢 ?

比如 poj 3984 迷宫问题

在 AC 之后, 写这篇博客不仅是为了供大家学习,斧正, 更是为了自身的总结, 吸取教训。

题目如下 :


我也在网上找了一些大神的方法, 可惜自己太菜, 完全看不懂啊, 最终经过自己的胡蒙乱凑终于找出了方法, 并把题AC 了, 嘿嘿嘿 。

在这里先说一下本菜鸡的失败经历 :(好丢人呀  (꒦_꒦)  )

① : 一开始想用map建立起两个结构体的映射的, 把每个子节点的父节点存起来, 最后一级一级地往上找,再逆向出就可以了。 

怎么杨, 这种想法是不是很棒。 

可是敲完后发现一编译就会出现一些奇怪的东西,(吐血.jpg)

请教大神后才发现原来map是有序的,又因为结构无法比较大小,所以要想实现需要结构体重载, 可是本菜鸡不会(留下 了不学无术的眼泪 · · ·)。

那就继续问度娘呗, 发现了一种叫做 unordered_map 的神奇无序版map(奸笑),哈哈哈, 眼瞅着就要做出来了,

而又双叒叕被打脸了,不知为啥编译还是无法通过, 一切都是自己想象啊。

至此, 本菜鸡不得不放弃这种方法。

②  : 睡觉之前, 我又冥思奇想了一种错误解法。 如果在结构体中定义 int 型的prex, prey , 在父节点 p 走到每个子点 t 时都使 t.prex = p.x;  t.prey = p.y , 这样打印时一级一级地返回就可以了。 无奈电脑已经关机, 只能第二天再试。 

醒来之后, 立马把那一坨代码敲了上去, 却发现只有前两个点的坐标是正确的, 后面点的坐标都与第二个点的坐标相同,至此, 本菜鸡居然还没有意识到自己究竟错在了那里。 我居然还傻不愣登 && 百思不得其解地 debug。 (真是佩自己的智商 o(╥﹏╥)o ) 

之后才发现, 因为返回时写的是 p.x = p.prex;  p.y = p.prey;  所以只改变了终点的坐标, 并没有返回父节点。 

至此, 第二种方法正式宣布流产。(555)

Finally, 在我冥(胡)思(蒙)苦(乱)想(造)之后, 终于敲出了解法, 如下 :

思维图化 :

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define PI acos(-1.0)
#define ll long long int
using namespace std;

const int M = 10;
bool a[M][M], vis[M][M];/// a 用来标记是否可走, vis 标记是否走过
struct node
{
    int x, y, time;
};
int Move[4][2] = {{0,-1},{0,1},{-1,0},{1,0}};///上下左右四个方向

void bfs()
{
    map<int, node>PRE[50];///建立起坐标与父节点的联系
    stack<int> st[2];///一个存 y ,一个存 x 并反向输出路径
    struct node p, t;
    queue<node> q;
    p.x = 0;
    p.y = 0;
    p.time = 0;
    q.push(p);
    vis[0][0] = 1;
    while(!q.empty())
    {
        p = q.front();
        q.pop();
        if(p.x == 4 && p.y == 4)/// end up 终点
            break;
        for(int i = 0; i < 4; ++i)
        {
            t = p;
            t.x += Move[i][0];
            t.y += Move[i][1];
            if(a[t.y][t.x] && !vis[t.y][t.x])///若此点可走且没有走过
            {///使用数组 a 的优点便体现在这里, 省去了判断边界的步骤。
                t.time++;
                PRE[t.y][t.x] = p;///标记 t 的父节点 
                q.push(t);
                vis[t.y][t.x] = 1;
            }
        }
    }
    int n = p.time + 1;
    while(n--)
    {
        st[0].push(p.y);///存入坐标
        st[1].push(p.x);
        p = PRE[p.y][p.x];///返回父节点
    }
    n = st[0].size();
    while(n--)
    {
        cout << '(' << st[0].top() << ", " << st[1].top() << ')' <<'\n';///利用栈的特性进行逆向打印
        st[0].pop();///弹出首元素
        st[1].pop();
    }
}

int main()
{
    memset(vis, 0, sizeof(vis));
    memset(a, 0, sizeof(a));///必须要初始化, 原因看下面
    int data;
    for(int i = 0; i < 5; ++i)
    {
        for(int j = 0; j < 5; ++j)
        {
            scanf("%d", &data);
            if(data == 0)
                a[i][j] = 1;///若 data 为 0,则说明此点可走,标记该点为 1.
            else
                a[i][j] = 0;
        }
    }
    bfs();
    return 0;
}

 

全部评论

相关推荐

06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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