您的位置:首页 > 其它

poj1324 - Holedox Moving(BFS+状态压缩)

2017-03-11 00:15 495 查看
题目链接:点击打开链接

题意:

一只长度为L的蛇要到达左上角的出口,问最短步数。

思路:

在最基本的bfs里,我们要记录每个状态是否已经访问过,在基础题里通常只是一个点,设置一个vis[x][y]=true就ok了。

在这题中,我们要把蛇身整体在某一位置看成一个状态,要表达L长度的身体,需要的空间很大,将是400^8;

我们把蛇头单独抽取出来,作为vis数组的前两维。第三维,我们将蛇的身体压缩到一个数字中,蛇的身体的每一节,相对于前面一节的位置,只有4种可能,即前后左右4种可能,蛇身最长为7,那么我们用两个2进制位(或者说4进制)表示每一节身体相对前一节的位置,然后左移两位,之后重复操作整个蛇身。那么压缩后,占用的空间为4^7=16384。

要注意的一点是,头不允许到达刚才尾巴的位置,如第一图中B1不能马上到达B4的位置。

失误:

将bfs出口放在了循环里,导致遗漏情况。

PS:

StatusAccepted
Time4688ms
Memory10944kB
Length2424
LangG++
Submitted2017-03-10 14:51:52
Shared
RemoteRunId16704097
太慢了..

代码:

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

using namespace std;

const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};
const int MAXN = 20+2;
int n, m, l;
bool tu[MAXN][MAXN];
bool vis[MAXN][MAXN][1<<14];

struct Tuple
{
int x, y;
};

struct Node
{
int step;
Tuple snake[8];
};

Node st;

inline bool judge(int x, int y, int z){
return (0<=x&&x<n && 0<=y&&y<m && !tu[x][y] && !vis[x][y][z]);
}

int getDirect(int x, int y, int tx, int ty){
if(x==tx){
if(y==ty-1) return 0;  //up
else return 1;         //down
}
else{
if(x-1==tx) return 2;  //left
else return 3;         //right
}
}

int cal(Node &t){
int ret = 0;
for(int i=1; i<l; ++i){
ret = (ret<<2) + getDirect(t.snake[i-1].x, t.snake[i-1].y, t.snake[i].x, t.snake[i].y);
}
return ret;
}

void SnakeMove(Node &now, Node &pre){
for(int i=1; i<l; ++i){
now.snake[i].x = pre.snake[i-1].x;
now.snake[i].y = pre.snake[i-1].y;
}
++now.step;
}

bool judgeBody(Node &now){
for(int i=1; i<l; ++i){
if(now.snake[i].x==now.snake[0].x && now.snake[i].y==now.snake[0].y)
return true;
}
return false;
}

int bfs(){
queue<Node> q;
st.step = 0;
q.push(st);
vis[st.snake[0].x][st.snake[0].y][cal(st)] = true;
while(!q.empty()){
Node temp = q.front(); q.pop();
for(int i=0; i<4; ++i){
Node now = temp;
now.snake[0].x += dx[i];
now.snake[0].y += dy[i];
int x = now.snake[0].x;
int y = now.snake[0].y;
if(x<0||y<0||x>=n||y>=m||tu[x][y]) continue;  //判断蛇头是否在边界内以及是否为石头

if(x==now.snake[l-1].x&&y==now.snake[l-1].y) continue; //特殊情况不允许头追尾
SnakeMove(now, temp);                  //move and step+1
if(judgeBody(now)) continue;           //判断蛇头是否和身体相撞

int z = cal(now);
if(vis[x][y][z]) continue;            //判断是否访问过
if(x==0&&y==0) return now.step;
q.push(now);
vis[x][y][z] = true;
}
}
return -1;
}

int main(){
int x, y, cas=0;
while(scanf("%d%d%d", &n, &m, &l)!=EOF){
if(n==0&&m==0&&l==0) break;
memset(tu, 0, sizeof(tu));
memset(vis, 0, sizeof(vis));
for(int i=0; i<l; ++i){
scanf("%d%d", &x, &y);
st.snake[i].x = x-1;
st.snake[i].y = y-1;
}
int stone;
scanf("%d", &stone);
for(int i=0; i<stone; ++i){
scanf("%d%d", &x, &y);
tu[x-1][y-1] = true;
}
if(st.snake[0].x==0 && st.snake[0].y==0)
printf("Case %d: %d\n", ++cas, 0);
else
printf("Case %d: %d\n", ++cas, bfs());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: