POJ 1324 [Holedox Moving] 状态压缩BFS

题目链接:http://poj.org/problem?id=1324

题目大意:n*m网格里有蛇和障碍,蛇只能向空格处移动,不能撞到自己,问到(1,1)的最短步数,如无法到达输出-1.

关键思想:不能直接对蛇头进行BFS,因为蛇身对蛇头的决策也有影响,故BFS时应该保存蛇身状态,我们放在state里用位运算来做。因为根据蛇头和每一节延伸的方向(东南西北)我们可以还原出整条蛇。比较坑的是这道题用pow会超时,自己写一个好啦。

由于vis数组很大,如果对于每个Case都初始化vis数组浪费时间,所以在申请了全局变量vis之后,我们对于每个kase,都只用当前的kase值去标记vis表示当前状态已出现.

#include <iostream>
#include <string.h>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;

typedef long long ll;

int n,m,L,K;
int Case=1; 
const int MAXN=21;
const int MAXM=21;
int M[MAXN][MAXM];
int dir[4][2]={0,1,1,0,0,-1,-1,0};
int vis[MAXN][MAXM][1<<14]={0};//蛇头在x,y的蛇状态 对应vis数组 

struct point{
    int x;
    int y;
    int step;
    int state;//二进制每两位表示一个方向(总共4个方向),共2*(L-1)位 
};

int snake[10][2]; 

int POW(int a,int n){
    int x=1;
    for(int i=0;i<n;i++){
        x*=a;
    }
    return x;
}

void SnakeMap(point a){//将蛇的状态再现到地图上 
    int x=a.x,y=a.y;
    int haha=3*POW(4,L-2);//位运算注意理解哦~ 
    int direction;
    M[x][y]=1;
    for(int i=0;i<L-1;i++){
        direction=(a.state&haha)/POW(4,L-2-i);
        M[x+=dir[direction][0]][y+=dir[direction][1]]=1;
        haha >>= 2;
    }
    return;
}

void recover(point a){//复原 
    int x=a.x,y=a.y;
    int haha=3*POW(4,L-2);
    int direction;
    M[x][y]=0;
    for(int i=0;i<L-1;i++){
        direction=(a.state&haha)/POW(4,L-2-i);
        M[x+=dir[direction][0]][y+=dir[direction][1]]=0;
        haha >>= 2;
    }
    return;
}

int BFS(){
    point First;
    First.x=snake[1][0],First.y=snake[1][1],First.step=0,First.state=0; 
    for(int i=2;i<=L;i++){
        if(snake[i][0]-snake[i-1][0]==1){
            First.state <<= 2;
            First.state+=1;
        }else if(snake[i][0]-snake[i-1][0]==-1){
            First.state <<= 2;
            First.state+=3;
        }else if(snake[i][1]-snake[i-1][1]==1){
            First.state <<= 2;
            First.state+=0;
        }else if(snake[i][1]-snake[i-1][1]==-1){
            First.state <<= 2;
            First.state+=2;
        }
    }//对state的处理,位运算 
    vis[First.x][First.y][First.state]=Case;
    //初始化第一个格局
    
    queue<point>q;
    q.push(First);
    point nw,nt;
    while(!q.empty()){
        nw=q.front();
        q.pop();
        if(nw.x==1&&nw.y==1)return nw.step;
        SnakeMap(nw);//蛇状态再现在地图上 
        for(int i=0;i<4;i++){
            nt.x=nw.x+dir[i][0],nt.y=nw.y+dir[i][1],nt.step=nw.step+1;
            nt.state=(nw.state/4+((i+2)%4)*POW(4,L-2));//公式是自己推的 
            if(nt.x<=n&&nt.x>=1&&nt.y<=m&&nt.y>=1&&M[nt.x][nt.y]==0&&vis[nt.x][nt.y][nt.state]!=Case){
                vis[nt.x][nt.y][nt.state]=Case;
                q.push(nt);
            }
        }
        recover(nw);//还原地图 
    }
    return -1;
}

 

int main(){    
    while(scanf("%d%d%d",&n,&m,&L)==3&&(n&&m&&L)){
        memset(M,0,sizeof(M));
        memset(snake,0,sizeof(snake));
        
        for(int i=1;i<=L;i++){
            scanf("%d%d",&snake[i][0],&snake[i][1]);
            M[snake[i][0]][snake[i][1]]=2;
        }
        scanf("%d",&K);
        for(int i=0;i<K;i++){
            int xx,yy;
            scanf("%d%d",&xx,&yy);
            M[xx][yy]=1;
        } 
        //地图输入完毕
        
        printf("Case %d: %d\n",Case++,BFS());
    }
    return 0;
}

 

posted @ 2017-08-18 12:48  哇咔咔咔  阅读(164)  评论(0编辑  收藏  举报