链接:http://poj.org/problem?id=1324
题意,给出蛇的位置和障碍物的位置,求蛇爬到(1,1)的最少步数
看了网上的博客才明白状态压缩的思路。第一次做状态压缩,因为一点小错误找了很久的错。
思路:
用一个结构体来存蛇的状态,3个数据,分别是蛇头的坐标(x,y),然后剩余的蛇身体用一个二进制数来表示。
用00,01,10,11可以表示4种状态,那么就可以将4个状态分别设置为这块身体相对于上一块身体的方向。
然后将这些二进制数连起来,所以就是一个最多14位的二进制数,转换为10进制,就能表示当前蛇的状态;
我设置的方向为go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
那么用00,01,10,11,来表示下,上,右,左
因为表示的方向是相对于上一块身体,那么要从上一块身体往下找身体的话,就是相对的方向;
如果用B1,B2,B3来表示蛇,B1在B2的上面,那么相对的,B2在B1的下面;
所以用一个数组来设置相反方向num[4] = { 1, 0, 3, 2 };与go数组的方向对应
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<map>
#include<cstring>
#include<iostream>
using namespace std;
int n, m, l;
int go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
int num[4] = { 1, 0, 3, 2 };
bool vis[22][22][(1 << 14) | 1];
int pic[22][22];
int base;
struct pos{
int x, y;
};
struct node{
int x, y, state, step;
};
bool judge(int x, int y)//判断是否越界以及是否有障碍物
{
if (x<1 || x>n || y<1 || y>m)
return false;
if (pic[x][y] == -1)
return false;
return true;
}
bool judgedir(int x, int y, int tx, int ty, int s)//tx,ty是目标方向,从蛇头往回找,看看是否会撞到自己身体
{
int k;
for (int i = 1; i < l; i++)
{
k = s & 3;
s >>= 2;
x += go[k][0];
y += go[k][1];
if (x == tx&&y == ty)
return false;
}
return true;
}
int getstate(pos a[])//求初始状态
{
int ans = 1;
int i, j;
for (i = l - 1; i >= 1; i--)
{
for (j = 0; j < 4; j++)
{
if (a[i].x == a[i - 1].x + go[j][0] && a[i].y == a[i - 1].y + go[j][1])
{
ans <<= 2;
ans |= j;
ans &= base;//去掉多余的长度
break;
}
}
}
return ans;
}
int BFS(int x, int y, int st)
{
queue<node> Q;
node start, use;
start.x = x;
start.y = y;
start.state = st;
start.step = 0;
Q.push(start);
vis[x][y][st] = true;
while (!Q.empty())
{
start = Q.front();
Q.pop();
if (start.x == 1 && start.y == 1)
return start.step;
use.step = start.step + 1;
int i;
for (i = 0; i < 4; i++)
{
use.x = start.x + go[i][0];
use.y = start.y + go[i][1];
if (judge(use.x, use.y) && judgedir(start.x, start.y, use.x, use.y, start.state))
{
use.state = start.state;
use.state <<= 2;
use.state |= num[i];
use.state &= base;
if (!vis[use.x][use.y][use.state])
{
vis[use.x][use.y][use.state] = true;
Q.push(use);
}
}
}
}
return -1;
}
int main()
{
// freopen("D://input.txt", "r", stdin);
int kase = 1;
while (scanf("%d%d%d", &n, &m, &l) != EOF&&n&&m&&l)
{
memset(pic, 0, sizeof(pic));
memset(vis, false, sizeof(vis));
base = (1 << (2 * (l - 1))) - 1;//当前使用的用来表示蛇的二进制数字的长度
pos firststate[10];//蛇身体的初始状态
int i;
for (i = 0; i < l; i++)
{
scanf("%d%d", &firststate[i].x, &firststate[i].y);
}
int num;
scanf("%d", &num);
while (num--)
{
int x, y;
scanf("%d%d", &x, &y);
pic[x][y] = -1;//障碍物设置-1
}
printf("Case %d: %d\n", kase++, BFS(firststate[0].x, firststate[0].y, getstate(firststate)));
}
return 0;
}
474

被折叠的 条评论
为什么被折叠?



