Codeforces 225D Snake(状压BFS)

传送门:http://codeforces.com/problemset/problem/225/D
题意:有一条蛇,头是1,然后按照234……的顺序趴在一个图上,问你蛇最少几步能吃到@。
思路:这题还是挺简单的,因为只要想到如何去保存蛇的状态就能做了。因为这题其实就是一个BFS,但是在BFS的过程中,你要知道这个蛇的当前状态是怎么样的。如果直接从1开始BFS,不管其余部位的话,在走了几步之后,蛇的剩余部位移动了以后就很难判断。
所以我们就可以想到,状压一条蛇。把一条蛇的形状状态压缩成三个数字。两个数字表示蛇头的x,y,剩下一个status用来保存蛇的剩余位置,但是由于每个位置都很难用一个数字保存。所以我们就可以想到保留相对位置,因为相对位置只有4种,上下左右,所以可以用二进制00,01,10,11来保存。假设一个蛇的长度为len,那么我们只要用(len-1)*2的一个二进制数来保存每个位置相对于他的上一个位置的数字。然后在每一次BFS的时候,将蛇的status左移两格,然后|=它的新位置的相对位置,再判断一下是否跟蛇的其他部位碰撞了。然后用一个vis[x][y][status]来保存当前位置是否访问过了,就可以轻松AC了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define pb push_back
#define mp make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF=2139062143;

const int maxn=20;
int n,m,maxlen;
ll base;
char pic[maxn][maxn];
bool vis[15][15][65536];
int go[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int rev[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
struct snake{
    int x,y;
    int status;
    snake():x(0),y(0),status(0){}
}start;
inline bool judge(int x,int y){
    return x>=0&&x<n&&y>=0&&y<m;
}
void startpos(){//计算出一开始蛇的状态,和一些其他数据
    maxlen=0;
    int x,y;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++)if(pic[i][j]!='#'&&pic[i][j]!='@'){
            if(pic[i][j]-'0'>maxlen){
                x=i;y=j;
                maxlen=pic[i][j]-'0';
            }
            if(pic[i][j]=='1'){
                start.x=i;start.y=j;
            }
        }
    }
    base=(1<<((maxlen-1)*2))-1;//蛇的最大长度所需要的全1二进制数,用来去掉多余位置的数据
    int &status=start.status;
    status=0;
    while(pic[x][y]!='1'){
        for(int i=0;i<4;i++){
            int xx=x+rev[i][0],yy=y+rev[i][1];
            if(judge(xx,yy)&&pic[xx][yy]==pic[x][y]-1){
                status<<=2;
                status|=i;
                x=xx;y=yy;
                break;
            }
        }
    }
}
#define F first
#define S second
bool bomb(int xx,int yy,snake s){//从蛇头开始移动,并判断是否发生碰撞
    int &status=s.status;
    int x=s.x,y=s.y;
    if(x==xx&&y==yy)return false;
    for(int i=1;i<maxlen-1;i++){
        x+=go[status&3][0];
        y+=go[status&3][1];
        status>>=2;
        if(x==xx&&y==yy)return false;
    }
    return true;
}
int BFS(){
    queue<pair<snake,int>> Q;
    Q.push(mp(start,0));
    vis[start.x][start.y][start.status]=true;
    while(!Q.empty()){
        snake st=Q.front().F;
        int step=Q.front().S;
        if(pic[st.x][st.y]=='@')return step;
        Q.pop();
        for(int i=0;i<4;i++){
            int xx=st.x+rev[i][0];
            int yy=st.y+rev[i][1];
            if(judge(xx,yy)&&pic[xx][yy]!='#'&&bomb(xx,yy,st)){
                snake next;
                next.x=xx;next.y=yy;
                next.status=((st.status<<2)&base)|i;
                if(!vis[xx][yy][next.status]){
                    vis[xx][yy][next.status]=true;
                    Q.push(mp(next,step+1));
                }
            }
        }
    }
    return -1;
}
int main(){
    //freopen("D://input.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%s",pic[i]);
    }
    startpos();
    printf("%d\n",BFS());
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值