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\n");//如果有答案的话,每一步的状态都保证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("\n");
    }
    if(nodes.size()%10 != 0) printf("\n");
}

好了,写完了。

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

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

posted @ 2020-07-20 18:01  LeoRanbom  阅读(284)  评论(0编辑  收藏  举报