HDU 4634 Swipe Bo

题目链接:Swipe Bo

解题思路:这个题目刚开始搞不清楚是为什么要判断两次方向,只能按照kuangbin大爷的写了。。。。。


根据代码来说第一个转向就是对于当前即将要扩展的节点进行一次方向判定,如果这个点不是转向标志的话,这里不起作用。

根据代码来说第二个转向就是对于下一节点进行判断,如果这里其作用的话,那么下一个循环的初始还会进行判断,那么这里就像当余无用了。


但是有一种情况就是,我当前节点是转向节点,走到了下一个节点又是一个转向节点,如果不对这个节点判断的话,就有可能出现不按照该方向节点指示的方向来走。方向就会错误。主要是影响触碰#的那一下。

##

RE

US

##

这种情况下,答案就会+1,然后成为WA自动机。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAX 220
#define MAXN 130

using namespace std;

struct node{
    int x, y, k, s;
    node(){}
    node(int xx, int yy, int kk, int ss){
        x = xx, y = yy, k = kk, s = ss;
    }
};

char g[MAX][MAX];
bool v1[MAX][MAX][MAXN][4];
bool v[MAX][MAX][MAXN];
int n, m, ans;
int kx[10], ky[10], ktot;
int sx, sy;
int dir[4][2] = {1,0,-1,0,0,1,0,-1};

void init(){
    ans = -1;
    ktot = 0;
}

int getKey(int x, int y){
    for(int i = 0; i < ktot; i++){
        if(kx[i] == x && ky[i] == y){
            return i;
        }
    }
    return -1;
}

int getDir(char c){
    if(c == 'D') return 0;
    if(c == 'U') return 1;
    if(c == 'R') return 2;
    if(c == 'L') return 3;
    return -1;
}

bool check(int x, int y){
    if(x < 0 || x >= n || y < 0 || y >= m){
        return false;
    }
    return true;
}

void bfs(){
    int i, j, k;
    queue<node> mq;
    memset(v, false, sizeof(v));
    memset(v1, false, sizeof(v1));
    mq.push(node(sx, sy, 0, 0));
    v[sx][sy][0] = true;
    while(!mq.empty()){
        node s = mq.front();
        //printf("%d %d %d %d\n", s.x, s.y, s.s, s.k);
        mq.pop();
        for(i = 0; i < 4; i++){
            int xx = s.x;
            int yy = s.y;
            int kk = s.k;
            int hh = i;
            while(1){
                //printf("$%d %d %d %d\n",i, xx, yy, hh);
                if(getDir(g[xx][yy]) != -1){
                    hh = getDir(g[xx][yy]);
                }
                if(v1[xx][yy][kk][hh]) break;
                v1[xx][yy][kk][hh] = true;
                xx += dir[hh][0];
                yy += dir[hh][1];
                if(!check(xx, yy))break;
                if(g[xx][yy] == '#')break;
                //printf("#%d %d %d %d\n", i, xx, yy, hh);
                if(g[xx][yy] == 'E' && kk == (1 << ktot) - 1){
                    ans = s.s + 1;
                    return;
                }
                if(getDir(g[xx][yy]) != -1){
                    hh = getDir(g[xx][yy]);
                    //printf("dir = %d %c\n", hh, g[xx][yy]);
                }
                if(g[xx][yy] == 'K'){
                    kk |= (1 << getKey(xx, yy));
                }
                if(check(xx + dir[hh][0], yy + dir[hh][1]) && g[xx + dir[hh][0]][yy + dir[hh][1]] == '#'){
                    //printf("in = %d %d %d %d\n", xx, yy, kk, hh);
                    if(v[xx][yy][kk])break;
                    mq.push(node(xx, yy, kk, s.s + 1));
                    v[xx][yy][kk] = true;
                    break;
                }
            }
        }

    }

}

int main(){
    int i, j, k;
    #ifndef ONLINE_JUDGE
    //freopen("1.in", "r", stdin);
    #endif // ONLINE_JUDGE
    while(~scanf("%d%d", &n, &m)){
        init();
        for(i = 0; i < n; i++){
            getchar();
            for(j = 0; j < m; j++){
                g[i][j] = getchar();
                if(g[i][j] == 'K'){
                    kx[ktot] = i;
                    ky[ktot++] = j;
                }
                if(g[i][j] == 'S'){
                    sx = i, sy = j;
                }
            }
        }
       // printf("%d %d\n", sx, sy);
        bfs();
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值