传送门: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;
}