蓝桥杯 算法练习 Abbott’s Revenge

问题描述
  在1999年的World Finals中有一个基于Dice Maze(骰子迷宫)的题目。在出题人编写那道题目的时候,他们并没有发现这种迷宫的创意来源。然而在那场比赛结束不久,创作了大量的这种迷宫的Robert Abbott先生,联系了比赛主办方并确认自己是骰子迷宫的原作者。我们很遗憾没有在去年的题目描述中感谢Abbott先生的原创意,但我们很高兴Abbott先生主动为今年的比赛提供他原创的、未公开的“步行通过的箭头迷宫”。
  与大多数的迷宫相同,箭头迷宫也是每次从一个路口走到另一个路口,直到到达终点。在每个路口处,如果你从某个方向进入了该路口,那么路口的地面上在靠近你的方向会画有一组箭头,它们相对于你的方向可以是向左,向前,向右,或者是它们的任意组合。
  图1描述了一个箭头迷宫。每个路口用二维坐标(x,y)表示,以左上角的路口为(1,1)。在图1给出的迷宫中,起点的坐标是(3,1),终点的坐标是(3,3)。在你开始后,你只能向北走1步到达(2,1)。由于你是从南边到达(2,1)这一点的,而这一点在南边的箭头是向前指的,所以你只能继续向前走到达(1,1)。在此之后,由于你是从南边到达了(1,1),这一点在南边的箭头是向右指的,所以你也只能向右拐,到达(1,2)。到目前为止,你还没有做出任何选择。以此类推,你会接着依次经过(2,2) (2,3) (1,3) (1,2)。现在你可以选择继续向前走或者向左转。如果你向前走,你会回到(1,1),而向左转可以让你到达(2,2)。事实上,唯一最优的方案是依次经过以下路口:(3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1) (2,2) (1,2) (1,3) (2,3) (3,3)。
  你需要写一个程序解决这个迷宫。“解决”的意义是:只要迷宫是可解的,你就要找到一条路线,它必须在起点沿指定的方向走出,并最终到达终点,当然,路线的长度需要是所有方案中最短的。
输入格式
  输入文件包括一个或多个箭头迷宫。每个迷宫描述的第一行是这个迷宫的名称,保证它只由数字和字母组成且长度不超过20。接下来的一行依次包含了起点的坐标,起始时方向,目标点的坐标,以空格隔开。本题的迷宫最大尺寸为9×9,所以行与列的编号均为1到9。起始时的方向为N,S,E,W之一,分别代表北、南、西、东。
  剩下的若干行按照以下格式输入:一对整数,若干字符串,以星号(*)结束,以空格隔开。每一行代表一个路口,一对整数表示路口的坐标。对于每一个字符串,第一位为N,S,E,W之一,接下来若干位只可能包含L,F,R,分别代表向左,向前,向右。这个字符串的含义是:朝向某个方向进入该路口(所以箭头被画在这个路口的相反方向),接下来就只能向某个方向继续行走。
  对于每个迷宫,以0作为一行的结束,从接下来一行开始就是一个新的箭头迷宫。输入文件以单独的一行END作为结尾。
输出格式
  对于每个箭头迷宫,应该先输出它的名字,然后接下来若干行,输出一个路径,格式如问题描述中所述;或者输出"No Solution Possible"。迷宫的名字应从第1列开始,而其余所有的行都从第3列开始,即行首有2个空格。对于输出的每个路径,除最后一行外,每行须输出恰好10个路口(坐标)。
  在下面的样例中,输入的第一个迷宫是图1中的迷宫。
  注意,在下面的样例输出当中,除了SAMPLE和NOSOLUTION两行以外,其余的行首都需要空两格!(由于格式化问题未能显示出来)
样例输入
SAMPLE
3 1 N 3 3
1 1 WL NR *
1 2 WLF NR ER *
1 3 NL ER *
2 1 SL WR NF *
2 2 SL WF ELF *
2 3 SFR EL *
0
NOSOLUTION
3 1 N 3 2
1 1 WL NR *
1 2 NL ER *
2 1 SL WR NFR *
2 2 SR EL *
0
END
样例输出
SAMPLE
(3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1)
(2,2) (1,2) (1,3) (2,3) (3,3)
NOSOLUTION
No Solution Possible
数据规模和约定
  设T为数据组数:对于30%的数据,T=1;对于60%的数据,T≤100;对于100%的数据,T≤1000。

算法是简单的BFS,就是数据处理较为麻烦。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int mapp[10][10];
//标记从某点出来向某个方向
bool vis[10][10][5];
//存储每个坐标四个方向的转弯情况
struct guide{
    bool dir[5][4];
    guide(){
        for(int i=0;i<5;i++){
            for(int j=0;j<4;j++)
                dir[i][j]=0;
        }
    }
};
//记录路径和过程中经历的点
struct node{
    int x,y;            //坐标
    string road;        //路径
    node(){
        road.clear();
    }
};
queue<node>qu;
//1,2,3,4分别代表东、西、南、北
int c_to_num(char ch){
    if(ch=='E') return 1;
    else if(ch=='W') return 2;
    else if(ch=='S') return 3;
    else return 4;
}
//1,2,3分别代表向左、向前、向右
int g_to_num(char ch){
    if(ch=='L') return 1;
    else if(ch=='F') return 2;
    else return 3;
}
bool judge(node now){
    if(now.x>0&&now.x<=9&&now.y>0&&now.y<=9&&!vis[now.x][now.y][now.road[now.road.size()-1]-'0'])
        return true;
    return false;
}
string bfs(int r,int s,guide *p){
    while(!qu.empty()){
        node now=qu.front(),next;
        qu.pop();
        if(now.x==r&&now.y==s) return now.road;
        int temp=mapp[now.x][now.y],cnt=now.road[now.road.size()-1]-'0';
        for(int i=1;i<=3;i++){
            next=now;
            if(p[temp].dir[cnt][i]){
                if(cnt==1){
                    switch(i){
                        case 1:next.x=now.x-1,next.road=now.road+char('0'+4);break;
                        case 2:next.y=now.y+1,next.road=now.road+char('0'+1);break;
                        case 3:next.x=now.x+1,next.road=now.road+char('0'+3);break;
                    }
                }
                else if(cnt==2){
                   switch(i){
                        case 1:next.x=now.x+1,next.road=now.road+char('0'+3);break;
                        case 2:next.y=now.y-1,next.road=now.road+char('0'+2);break;
                        case 3:next.x=now.x-1,next.road=now.road+char('0'+4);break;
                    }
                }
                else if(cnt==3){
                    switch(i){
                        case 1:next.y=now.y+1,next.road=now.road+char('0'+1);break;
                        case 2:next.x=now.x+1,next.road=now.road+char('0'+3);break;
                        case 3:next.y=now.y-1,next.road=now.road+char('0'+2);break;
                    }
                }
                else {
                    switch(i){
                        case 1:next.y=now.y-1,next.road=now.road+char('0'+2);break;
                        case 2:next.x=now.x-1,next.road=now.road+char('0'+4);break;
                        case 3:next.y=now.y+1,next.road=now.road+char('0'+1);break;
                    }
                }
                if(judge(next)){
                    vis[next.x][next.y][next.road[next.road.size()-1]-'0']=1;
                    qu.push(next);
                }
            }
        }
    }
    return "-1";
}
int main() {
    string name;
    while(cin>>name&&name!="END"){
        while(!qu.empty()) qu.pop();
        memset(mapp,0,sizeof(mapp));
        memset(vis,0,sizeof(vis));
        guide *p=new guide[100];
        node start;
        int m,n,r,s;
        char sr;
        scanf("%d%d%*c%c%*c%d%d",&m,&n,&sr,&r,&s);
        if(sr=='N') start.x=m-1,start.y=n,start.road+=char('0'+4);
        else if(sr=='S') start.x=m+1,start.y=n,start.road+=char('0'+3);
        else if(sr=='E') start.x=m,start.y=n+1,start.road+=char('0'+1);
        else start.x=m,start.y=n-1,start.road+=char('0'+2);
        vis[start.x][start.y][start.road[start.road.size()-1]-'0']=1;
        qu.push(start);
        int id=1,x,y;
        string ifo;
        while(scanf("%d",&x)&&x){
            scanf("%d",&y);
            mapp[x][y]=id;
            while(cin>>ifo&&ifo[0]!='*'){
                int len=ifo.size();
                int temp=c_to_num(ifo[0]);
                for(int i=1;i<len;i++){
                    p[id].dir[temp][g_to_num(ifo[i])]=true;
                }
            }
            id++;
        }
        string ans=bfs(r,s,p);
        cout<<name<<endl;
        if(ans=="-1"){
            cout<<"  No Solution Possible"<<endl;
            continue;
        }
        cout<<"  ("<<m<<','<<n<<')';
        int len=ans.size();
        for(int i=0;i<len;i++){
            if(i%10==9){
                cout<<endl;
                cout<<" ";
            }
            if(ans[i]=='1') n+=1;
            else if(ans[i]=='2') n-=1;
            else if(ans[i]=='3') m+=1;
            else m-=1;
            cout<<" ("<<m<<','<<n<<')';
        }
        cout<<endl;
    }
    return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值