POJ 1324 Holedox Moving 位运算+BFS

POJ 1324 Holedox Moving

题目描述:

  题目链接:POJ 1324 Holedox Moving

题目大意:

  给定贪吃蛇的初始位置和洞穴中的石头的位置,问这个贪吃蛇到达洞口的最短时间。如果不能到达输出 1

解题思路:

  这个题的难点在于对贪吃蛇状态的记录以及对蛇的状态的判重。由题知蛇长最大为7因此,我们可以用一个整数(int)的二进制来表示蛇的形态。每一格相对于其上一格的方向有四种即上下左右,我们可以分别用 00011011 来表示。通过位运算的方式将其置于int的前14位。因此只要开一个最大为 vis[22][22][1<<15] 的数组即可。然后进行bfs搜索。

复杂度分析:

时间复杂度 : O(nml)
空间复杂度 : O(nml)

AC代码:

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<cstdio>

using namespace std;
struct state{
    int x[10],y[10];
}s;

struct node{
    int x,y,s,k;
};

int n,m,l,k;
int vis[22][22][1<<15];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int gm[22][22];

state decode(int x, int y, int s, int l){
    int dire;
    state pos;
    pos.x[0] = x;
    pos.y[0] = y;
    for(int i = 1; i < l; i++){
        dire = 3;
        dire &= s;
        s >>= 2;
        pos.x[i] = pos.x[i-1]+dir[dire][0];
        pos.y[i] = pos.y[i-1]+dir[dire][1];
    }
    return pos;
}

int encode(state s, int l){
    int st = 0;
    for(int i = l - 1; i > 0; i--){
        int x,y,now;
        x = s.x[i] - s.x[i-1];
        y = s.y[i] - s.y[i-1];
        if(x == 1 && y == 0)  now = 0;
        else if(x == -1 && y == 0) now = 1;
        else if(x == 0 && y == 1)  now = 2;
        else if(x == 0 && y == -1) now = 3;
        st <<= 2;
        st |= now;
    }
    return st;
}

node moves(node s, int d, int l){
    int mod = (1 << ((l - 1) * 2)) - 1;
    int now;
    int nx,ny,x,y;
    nx = s.x + dir[d][0];
    ny = s.y + dir[d][1];
    x = -dir[d][0];
    y = -dir[d][1];
    if(x == 1 && y == 0)  now = 0;
    else if(x == -1 && y == 0) now = 1;
    else if(x == 0 && y == 1)  now = 2;
    else if(x == 0 && y == -1) now = 3;
    s.s <<= 2;
    s.s |= now;
    s.s &= mod;
    s.x = nx;
    s.y = ny;
    return s;
}
bool judge(int x, int y, int s, node pre){
    if(x < 1 || x > n || y < 1 || y > m) return false;  //越界检查
    if(vis[x][y][s] == 1) return false;  //移动之后自己还占着那个地方
    if(gm[x][y] == 1) return false;  //路被占
    state sx = decode(pre.x, pre.y, pre.s,l);
    for(int i = 0; i < l; i++)
        if(sx.x[i] == x && sx.y[i] == y) return false;
    return true;
}

int bfs()
{
    queue<node> q;
    node a, tp;
    a.x = s.x[0],a.y = s.y[0];
    a.s = encode(s,l);
    a.k = 0;
    q.push(a);
    vis[a.x][a.y][a.s] = 1;
    while(!q.empty())
    {
        a = q.front();
        q.pop();
        if(a.x == 1 && a.y == 1)
            return a.k;
        for(int i=0;i<4;i++)
        {
            tp = moves(a,i,l);
            tp.k = a.k+1;
            if(!judge(tp.x,tp.y,tp.s,a)) continue;
            vis[tp.x][tp.y][tp.s] = 1;
            q.push(tp);
        }
    }
    return -1;

}
int main(){
    int kase = 0;
    while(scanf("%d%d%d",&n,&m,&l) == 3){
        if(!(n||m||l))return 0;
        memset(vis,false,sizeof(vis));
        memset(gm,0,sizeof(gm));
        for(int i = 0; i < l;i++){
            scanf("%d%d",&s.x[i],&s.y[i]);
        }
        int x,y;
        scanf("%d",&k);
        for(int i = 0; i < k;i++){
            scanf("%d%d",&x,&y);
            gm[x][y] = 1;
        }
        printf("Case %d: %d\n",++kase,bfs());
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值