• uva816


    Uva 816. Abbott的复仇(BFS求最短路)

    //完全参考刘汝佳算法竞赛入门经典
    

    首先来看看题,从不同方向(北东南西NESW)进入不同节点后,它可以做的操作(直行F,左拐L,右拐R)是不同的。

    设每次移动是从 出发点 ---》 目标点

    const char* dirs = "NESW";//设立北0东1南2西3
    const char* turns = "FLR";//这块结合后面操作。如果直行的话,出发点的dir和目标点一样;如果左转的话,目标点的dir 比 出发点的dir小1;右转的话则大1。
    int dir_id(char c){
    	return strchr(dirs,c) - dirs;
    } //获得字符c的位置(是第几个——int数据)
    int turn_id(char c){
    	return strchr(turns,c) - turns;
    } 
    

    接下来进行 “行走”函数

    int dx[] = {-1,0,1,0};
    int dy[] = {0,1,0,-1};
    
    Node walk(const Node& u,int turn){//注意,Node结构体已经包含了来自的方向,所以不需要再加 方向
        if(turn = 0)int dir = u.dir;
        if(turn = 1)int dir = (u.dir + 3)%4;//本来应该是-1,但是负数无法取模,所以顺时针转3个单位==逆时针转1个单位。
        if(turn = 2)int dir = (u.dir + 1)%4
        return Node(u.r + dx[dir],u.c+dy[dir])
    }//如果  目标点.dir =N北,那么出发点肯定在目标点的北方,所以“目标点.y = 出发点.y - 1",同理其他方位也可以得出来相应的差。
    

    接下来搞输入部分,分析一下输入的数据

    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 //以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 //以END作为示例名称标志着程序程序整体结束。

    把数据都读入

    bool input(){
        
        memset(has_edge, 0, sizeof(has_edge));
        cin >> name;//示例名字
        if(name == "END") return false;
        char s[100];
        cin >> r0 >> c0 >> s >> r2 >> c2;//输入起始和目标位置
        cout << name << endl;//直接先输出名字
        r1 = r0 + dy[dir_id(s[0])];
        c1 = c0 + dx[dir_id(s[0])];
        dir = dir_id(s[0]);
        int r, c;
        while(cin >> r){
            if(r == 0) break;
            cin >> c;
            char s2[100];
            while(cin >> s2){//循环读入一个节点某个方向的可以转的方向
                if(s2[0] == '*') break;//当输入*时,此节点结束
                int l  = strlen(s2);
                for(int i = 1; i < l; ++i){
                    has_edge[r][c][dir_id(s2[0])][turn_id(s2[i])] = 1;
                }
            }
        }
        return true;//全都输入完毕,返回true,然后继续下一次示例
    }
    

    再来一发BFS主体:

    void solve(){
        queue<Node> q;
        memset(d, -1, sizeof(d));
        Node u(r1, c1, dir);
        d[u.r][r.c][u.dir] = 0;
        q.push(u);
        while(!q.empty()){
            Node u = q.front();
            q.pop();
            if(u.r == r2 && u.c == c2) {//达到目的地时的状态:q有1个——q进行判断,是目标节点——输出,并返回,
                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
    ");//如果有答案的话,每一步的状态都保证q非空(包括目标和起始位置那一步)
    }
    

    再把解的路线输出出来。

    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));
        
        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("
    ");
    }
    

    好了,写完了。

    其中输入处理的时候,不小心把s2写成了s,c写成了r,导致了错误,改回来了

    但是vj上一直WA,去debug找了一下这道题的数据点,和我的对比了一下,也是一样的。不知道是哪里出了问题。

  • 相关阅读:
    paip.数据库全文检索 attilax总结
    软件网站安全性的设计与检测与解决方案
    防止SQL注入解决方案
    paip.账务系统的安全性
    快速开发字段很多的MIS表
    paip.php调试不能显示局部变量内容w/ xdebug
    程序安全性之配置文件安全
    paip.VS2010未能加载类型
    paip.盘古汉字转拼音组件库使用总结
    paip.跟踪DISCUZ积分日志功能总结
  • 原文地址:https://www.cnblogs.com/ranbom/p/13346470.html
Copyright © 2020-2023  润新知