Uva Abbott’s Revenge 816

还是曾经看不懂的一个题目。如今回头看起来 水死了 ,可是好像让我写也是写不出来的。对比着网上的实现。也算所有理解了,代码都经过我具体凝视。

里面感觉有非常多 搜索的惯用思维方法。应该学会怎样把这样的常见问题抽象成代码方案。

比方怎样推断行走的方法。学会怎么刻画最短路径搜索树!

#include<iostream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<cctype>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>

using namespace std;
const int INF=0x1f1f1f1f;
const double pi=4*atan(1);
const int Maxn=200+10;

int dr[]= {-1,0,1,0};//两数组控制行数和列数,此程序中
int dc[]= {0,1,0,-1};//数组元素特定

struct Node    //每个节点的属性集合 包括横纵坐标和 面朝方向
{
    //这里的方面dir是int值相应方向char数组元素下标
    int r,c,dir;
    Node(int rr,int cc,int dirr):r(rr),c(cc),dir(dirr) {}
    Node() {}
};

const char *dirs="NESW";    // 常量数组运用
const char *turns="FLR";
bool has_edge[10][10][4][4];// 前两个元素表示横纵坐标,第三四个分别表示面朝某一方向时,能否够转弯
int d[10][10][4];         // bfs时,记录行走长度
int r1,c1,r2,c2,dir;
int r0,c0;
bool flag;
Node p[10][10][4];   //保存最短路径树的父节点,记录路径

int dir_id(char ch)      //  将字符方向双射到int表示的方向
{
    return strchr(dirs,ch)-dirs;
}

int turn_id(char ch)   //  相同把用字符表示的向哪儿转双射到int上
{
    return strchr(turns,ch)-turns;
}
//依据当前状态,和所要转弯方式。计算后继状态:
//行走函数:
Node walk(Node &u,int turn )
{
    int dd=u.dir;
    if(turn==1)  // 逆时针
        dd=(dd+3)%4;
    else if(turn == 2)  //顺时针
        dd=(dd+1)%4;
    return Node(u.r+dr[dd],u.c+dc[dd],dd);// 返回后继状态
}
//从目标结点逆序追溯到初始结点
void print_ans(Node u)
{
    vector<Node>nodes;
    while(1)
    {
        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));
    int cnt=0;
    for(int i=nodes.size()-1; i>=0; i--)
    {
        if(cnt%10==0)
            cout<<" ";
        cout<<" ("<<nodes[i].r<<","<<nodes[i].c<<")";
        if(++cnt%10==0)
            cout<<endl;
    }
    if(nodes.size()%10!=0)
        cout<<endl;
}

bool inside(int r,int c)
{
    if(r>0&&r<10&&c>0&&c<10)
        return true ;
    return false;
}

void solve()
{
    queue<Node>q;
    memset(d,-1,sizeof(d));
    memset(p,0,sizeof(p));
    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) //发现终点退出
        {
            flag=0;
            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);
            }
        }
    }
    printf("  No Solution Possible\n");
}


int main()
{
    char str[30];
    while(scanf("%s",str)&&strcmp(str,"END"))
    {
        flag=1;
        memset(has_edge,0,sizeof(has_edge));
        char ch;
        cin>>r0>>c0>>ch>>r2>>c2;
        dir=dir_id(ch);
        r1=r0+dr[dir];
        c1=c0+dc[dir];
        int r,c;
        char str2[30];

        while(cin>>r)
        {
            if(r==0)
                break;
            cin>>c;
            while(cin>>str2)
            {
                if(str2[0]=='*')
                    break;
                int dirID=dir_id(str2[0]);
                int len=strlen(str2);
                for(int i=1; i<len; i++)
                {
                    int turnID=turn_id(str2[i]);
                    has_edge[r][c][dirID][turnID]=1;
                }
            }
        }
        printf("%s\n",str);
        solve();
    }
    return 0;
}



posted @ 2017-04-18 18:30  jzdwajue  阅读(170)  评论(0编辑  收藏  举报