• Abbott's Revenge UVA


    题目链接:https://vjudge.net/problem/UVA-816

     

     题目大意: 有一个最多包含9*9 个交叉点的迷宫。输入起点,离开起点时的朝向和终点,求一条最短路(多解时任意输出 一个即可)

    思路:  这个迷宫的特殊之处其实就两点,一是朝向会影响往哪走,而是要记录走的路径。

    所以我们要解决这两个难点:

    朝向  :我们可以给数组再加一个朝向 来标记是否访问过

    记录路径:可以 记录当前节点的父亲节点,注意当前节点是加 了朝向的当前节点

    这是写过的第一道要输出路径的题目,很重用!!!

    看代码:

    #include<iostream>
    #include<string.h>
    #include<queue>
    #include<stdio.h>
    using namespace std;
    const int maxn=9+5;
    
    struct Node
    {
        int r,c,dir;//该位置的坐标 和 上一个位置走dir方向到这里
        Node(int r=0,int c=0,int dir=0):r(r),c(c),dir(dir){}//构造函数
    };
    
    /**
    将四个方向和3种“转弯方式”编号  并且提供相应的转换函数
    **/
    const char* dirs="NESW";//顺时针旋转  下标0-3
    const char* turns="FLR";//下标0-2
    int dir_id(char c){return strchr(dirs,c)-dirs;}//找到该字符出现的位置
    int turn_id(char c){return strchr(turns,c)-turns;}
    
    int d[maxn][maxn][maxn];//第一个位置到该位置的距离
    int has_edge[maxn][maxn][maxn][maxn];//该节点到下一个地方是否有路
    Node p[maxn][maxn][maxn];//该节点的父亲节点
    int r0,c0,r1,c1,dir,r2,c2;//起点 下一个节点 终点
    string maze_name;//名字
    
    /**
    接下来是"行走"函数,根据当前状态和转弯方式  计算出后继状态
    **/
    const int dr[]={-1,0,1,0};//注意顺序不能变 与之前的dirs相对应的
    const int dc[]={0,1,0,-1};
    
    Node walk(const Node& u,int turn)
    {
        int dir=u.dir;
        if(turn==1) dir=(dir+3)%4;//逆时针  往左走  不管哪个方向 加上3就是它的左边
        if(turn==2) dir=(dir+1)%4;//顺时针
        return Node(u.r+dr[dir],u.c+dc[dir],dir);//下一个节点的坐标 和 从哪来
    }
    
    /**
    inside
    **/
    bool inside(int r,int c)
    {
        if(r>=1&&r<=9&&c>=1&&c<=9) return true;
        return false;
    }
    
    
    
    /**
    最后是解的打印过程。它也可以写成递归函数 不过用vector保存结点可以避免递归时出现栈溢出,并且更加灵活
    **/
    void print_ans(Node u)
    {
        //从目标结点逆序追溯到初始结点
        vector<Node> nodes;
        for(;;)//一直找到除起点外的第一个位置
        {
            nodes.push_back(u);
            if(d[u.r][u.c][u.dir]==0) break;
            u=p[u.r][u.c][u.dir];
        }
        nodes.push_back(Node(r0,c0,dir));//起点
    
        cout<<maze_name<<endl;
    
        //打印解
        int cnt=0;
        for(int i=nodes.size()-1;i>=0;i--)
        {
            if(cnt%10==0) printf(" ");
            printf(" (%d,%d)",nodes[i].r,nodes[i].c);
            if(++cnt%10==0) printf("
    ");
    
        }
        if(nodes.size()%10!=0) printf("
    ");
        return ;
    }
    
    /**
    下面是bfs主过程
    **/
    void solve()
    {
        queue<Node> q;
        memset(d,-1,sizeof(d));
        Node u(r1,c1,dir);//起点走到的第一个位置
        d[u.r][u.c][u.dir]=0;
        q.push(u);
        while(!q.empty())
        {
            Node u=q.front();
            q.pop();
            if(u.r==r2&&u.c==c2){print_ans(u);return ;}//走到了终点 可以打印路径了 
            for(int i=0;i<3;i++)//判断三个方向是否可以走
            {
                Node v=walk(u,i);//找到下一个位置的坐标和 从哪来
                if(has_edge[u.r][u.c][u.dir][i]&&inside(v.r,v.c)&&d[v.r][v.c][v.dir]<0)//往这个方向有路 并且 这条路合法 并且 没有走过
                {
                    d[v.r][v.c][v.dir]=d[u.r][u.c][u.dir]+1;//距离加一
                    p[v.r][v.c][v.dir]=u;//存储当前节点的父亲节点
                    q.push(v);//当前节点入队列
                }
            }
        }
        cout<<maze_name<<endl;
        printf("  No Solution Possible
    ");
    }
    
    /**
    输入函数比较简单 作用就是读取r0,c0,dir,并且计算出r1,c1  然后读入has_edge数组中
    其中has_edge[r][c][dtr][turn]表示当前状态是(r,c,dir)  是否可以沿着转弯方向turn行走
    **/
    void read_edge()
    {
        memset(has_edge,0,sizeof(has_edge));//初始化  全都为没有走过
        int pr,pc,pdir,pturn;
        string temp;
        while(cin>>pr)
        {
            if(pr==0) break;
            cin>>pc;
            while(cin>>temp)
            {
                if(temp=="*") break;
                pdir=dir_id(temp[0]);//从哪个方向来的
                for(int i=1;i<temp.length();i++)
                {
                    pturn=turn_id(temp[i]);
                    has_edge[pr][pc][pdir][pturn]=1;//往哪个方向走有路
                }
            }
        }
    }
    
    /**
    输入函数
    **/
    bool read_list()
    {
        cin>>maze_name;//名字
        if(maze_name=="END") return false;
        char dir0;
        cin>>r0>>c0>>dir0>>r2>>c2;//初始位置 方向  结束位置
        dir=dir_id(dir0);//计算下一个位置在哪
        r1=r0+dr[dir];
        c1=c0+dc[dir];
        read_edge();
        return true;
    }
    
    int main()
    {
        while(read_list())
        {
            solve();
        }
        return 0;
    }

    其实自己也把这道题写出来了,代码将近写了300行,但是虽然结果正确了,但是交上去却显示re   找了很久的Bug  没找出来,无奈之下看了题解才过掉

    到现在自己也没有找出Bug在哪 ,还是自己太菜了

    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    4.1.4协变和逆变 不常用
    4.1.33匿名方法Lambda语法
    4.1.1委托和广播
    1.4.3用户定义异常类
    1.4.2异常处理
    1.3.6接口判断及显式实现比较
    常用正则表达式
    git
    Pod 操作
    C语言指针的初始化和赋值
  • 原文地址:https://www.cnblogs.com/caijiaming/p/10387620.html
Copyright © 2020-2023  润新知