UVA816 Abbott的复仇 Abbott‘s Revenge

这个题是一个很经典的BFS求图最短路的问题,复杂一点的就是加了个朝向。这个题细节很多而且输出格式巨坑。贴AC代码,解释都在注释里

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10;
int d[maxn][maxn][4]; // 记录初始状态到这时的长度,三个值分别为横、纵坐标、朝向


string name; //迷宫名字
int has_edge[maxn][maxn][4][4]; //记录某个点可以往什么方向走
const char *dirs = "NESW";
const char *turns = "FLR";
// 这个题真的麻烦

// 方便判断每一次行走后新的点的位置
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, 1, 0, -1};
// 构造一个结构体来存点
struct Node
{
    int r,c,d;
    Node(int r_=0,int c_=0,int d_=0){
		r=r_;
		c=c_;
		d=d_;
	};
    Node& operator=(const Node & cp) {
        this->r = cp.r;
        this->c = cp.c;
        this->d = cp.d;
        return *this;
    }
};
Node startPoint,nowPoint,desPoint; // 起始点、现在所在点、目的点
Node p[maxn][maxn][4]; // 记录父节点,方便回溯输出路径
int dir_id(char c) 
{ 
    return strchr(dirs, c) - dirs; 
}
int turns_id(char c) { 
    return strchr(turns, c) - turns; 
}

// 输入函数
bool input()
{
    memset(has_edge,0,sizeof(has_edge));
    cin>>name;
    if(name=="END") 
        return false;
    char tmpd;
    cin>>startPoint.r>>startPoint.c>>tmpd>>desPoint.r>>desPoint.c;
    nowPoint.d = dir_id(tmpd); // 注意是当前点而不是初始点

    // 下面两行代码可能有点难理解,多思考一下
    // 面朝南方则行加一,面朝北方则行减一,面朝东或西则行数不变
    // 因为刚开始的时候只能朝当前方向直行,所以可以这么写
    nowPoint.r = startPoint.r + dr[nowPoint.d];
    nowPoint.c = startPoint.c + dc[nowPoint.d];
    int tmpr,tmpc;
    string s;
    while(cin>>tmpr && tmpr) { 
        cin>>tmpc;
        while(cin>>s&&s!="*") {
            for(int i = 1; i < s.length(); i++)
                has_edge[tmpr][tmpc][dir_id(s[0])][turns_id(s[i])] = 1; // 本质上就是构图
        }
    }
    return true;
};
// 万里长征走完第一步了,输入函数写完了
// 接下来写走路的函数
Node walk(const Node &present, int turn) {
    int dic = present.d;
    // turn为0是直行,所以方向不改变
    if(turn==1)//左转
        dic = (dic+3)%4;
    if(turn==2)
        dic = (dic+1)%4;
    return Node(present.r+dr[dic],present.c+dc[dic],dic);
};

// 判断是否在图内
bool inside(int r, int c) {
    return r > 0 && c > 0 && r < maxn && c < maxn;
};



// 输出函数他来了
void print_ans(Node&u)
{
    stack<Node> arr;
    while(true) {
        arr.push(u);
        if(d[u.r][u.c][u.d]==0)
            break;
        u = p[u.r][u.c][u.d];
    }
    arr.push(startPoint); // 千万别忘记初始点
    int cnt = 0;
    int s = arr.size();
    while(!arr.empty()) {
        Node tmp = arr.top();
        arr.pop();
        if(cnt%10==0)
            cout<<"  ";
        else
            cout<<" ";
        cout<<"("<<tmp.r<<","<<tmp.c<<")";
        cnt++;
        if(cnt%10==0) 
            cout<<endl;
    }
    if(s % 10 !=0)
        cout<<endl;
};
void solve()
{
    queue<Node> q;
    cout<<name<<endl;
    memset(d,-1,sizeof(d)); // 记得清空
    Node u = nowPoint; // 要记得刚开始的时候,现在的点不是初始点,而是初始点朝前走的一个点
    d[u.r][u.c][u.d]=0; // 想清楚为什么是这里为0
    q.push(u);
    while(!q.empty()) {
        u = q.front();
        q.pop();
        if(u.r==desPoint.r&&u.c==desPoint.c) {
            print_ans(u);
            return;
        }
        for(int i = 0; i<3; i++) { // 看三个方向哪个可以走
            Node v = walk(u,i);
            if(has_edge[u.r][u.c][u.d][i]&&inside(v.r,v.c)&&d[v.r][v.c][v.d]==-1) {
                d[v.r][v.c][v.d] = d[u.r][u.c][u.d] + 1;
                p[v.r][v.c][v.d] = u;
                q.push(v);
            }
        }

    }
    cout << "  No Solution Possible" << endl; // 前面有两个空格,坑的一批
    return;
};
int main()
{
    while(input()) 
        solve();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值