很久之前就看到这道题了~~但是困于能力的问题~~~也没想到居然要状压~~~
蛇头每走一步,相邻的蛇身就会占领前一节蛇头/身所在的位置。因为蛇身只会只有4个方向可以前进,所以我们可以用0、1、2、3代表蛇身的相对前进方向。
这就需要两位二进制。。由于蛇身最多7节,2<<(2*7)=16384 继而20*20*16384是可以接受的状态数量~~
int ans[21][21][16400];///ans[i][j][k]:=i,j代表舌头所在地方~~k代表蛇身是怎么摆放的~~
///蛇身相对于前一块、要么向左0、要么向右1、要么向下2、要么向上3 所以每两位二进制代表当前蛇身的行进方向
///继而可以推出蛇的样子
操作顺序:
先初始化蛇身的前进方向。放进队列。
如果队列不为空、找出蛇头可以前进的方向、更新点并放入队列
这里一些优化,第一次找到(1,1)就可以break了~~
而且状态只需要遍历一次就可以了~~
#include <algorithm>
#include <iostream>
#include<string.h>
#include <fstream>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define exp 1e-8
#define fi first
#define se second
#define ll long long
#define INF 0x3f3f3f3f
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define all(a) a.begin(),a.end()
#define mm(a,b) memset(a,b,sizeof(a));
#define for0(a,b) for(int a=0;a<=b;a++)//0---(b-1)
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define rep(a,b,c) for(int a=b;a<=c;a++)//b---c
#define repp(a,b,c)for(int a=b;a>=c;a--)///
#define cnt_one(i) __builtin_popcount(i)
#define stl(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
using namespace std;
void bug(string m="here"){cout<<m<<endl;}
template<typename __ll> inline void READ(__ll &m){__ll x=0,f=1;char ch=getchar();while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}m=x*f;}
template<typename __ll>inline void read(__ll &m){READ(m);}
template<typename __ll>inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c){READ(m);READ(a);READ(b);READ(c);}
template<typename __ll>inline void read(__ll &m,__ll &a,__ll &b,__ll &c,__ll &d){READ(m);READ(a);READ(b);READ(c);read(d);}
template < class T > inline void out(T a){if(a>9)out(a/10);putchar(a%10+'0');}
template < class T > inline void outln(T a){if(a>9)out(a/10);putchar(a%10+'0');puts("");}
template < class T > inline void out(T a,T b){out(a);putchar(' ');out(b);}
template < class T > inline void outln(T a,T b){out(a);putchar(' ');outln(b);}
template < class T > inline void out(T a,T b,T c){out(a);putchar(' ');out(b);putchar(' ');out(c);}
template < class T > inline void outln(T a,T b,T c){out(a);putchar(' ');outln(b);putchar(' ');outln(b);}
template < class T > T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template < class T > T lcm(T a, T b) { return a / gcd(a, b) * b; }
template < class T > inline void rmin(T &a, const T &b) { if(a > b) a = b; }
template < class T > inline void rmax(T &a, const T &b) { if(a < b) a = b; }
template < class T > T pow(T a, T b) { T r = 1; while(b > 0) { if(b & 1) r = r * a; a = a * a; b /= 2; } return r; }
template < class T > T pow(T a, T b, T mod) { T r = 1; while(b > 0) { if(b & 1) r = r * a % mod; a = a * a % mod; b /= 2; } return r; }
const int l=0;
const int r=1;
const int down=2;
const int up=3;
int ans[21][21][16400];///ans[i][j][k]:=i,j代表舌头所在地方~~k代表蛇身是怎么摆放的~~
///蛇身相对于前一块、要么向左0、要么向右1、要么向下2、要么向上3 所以每两位二进制代表当前蛇身的行进方向
///继而可以推出蛇的样子
bool vis[21][21][16400];
bool block[21][21];
int snake[10][3];
int dx[]={1,-1,0,0};///0下 1上 2右 3左
int dy[]={0,0,1,-1};
int OR[]={2,3,1,0};
int haha[]={0,0,3,15,63,255,1023,4095,16383};
int togo[4];
int n,m,L;
struct DAT
{
int a,b,c;
DAT(){}
DAT(int _a,int _b,int _c)
{
a=_a;b=_b;c=_c;
}
}cur;
void get_togo(int state)
{
mm(togo,1);
int x=0,y=0;
int cnt=4;
for(int i=1;i<L;i++)
{
switch(((state>>2*(i-1)))&3)
{
case down:
x++;break;
case up:
x--;break;
case l:
y++;break;
case r:
y--;break;
default:
break;
}
if(y==0&&x==1)///不能往上走
togo[1]=0,cnt--;
if(y==0&&x==-1)
togo[0]=0,cnt--;
if(x==0&&y==1)
togo[2]=0,cnt--;
if(x==0&&y==-1)
togo[3]=0,cnt--;
if(cnt==0)break;
}
}
int initstate()
{
int state=0;
int now=0;
for(int i=2;i<=L;i++)
{
if(snake[i][1]==snake[i-1][1])///x相等~~
{
if(snake[i][2]+1==snake[i-1][2])
state|=r<<(2*now);
else if(snake[i][2]==snake[i-1][2]+1)
state|=l<<(2*now);
}
else if(snake[i][2]==snake[i-1][2])
{
if(snake[i][1]+1==snake[i-1][1])
state|=down<<(2*now);
else if(snake[i][1]==snake[i-1][1]+1)
state|=up<<(2*now);
}
now++;
}
return state;
}
int dfs()
{
mm(vis,0);
mm(ans,INF);
queue<DAT>que;
cur=DAT(snake[1][1],snake[1][2],initstate());
if(snake[1][1]==1&&snake[1][2]==1)return 0;
vis[cur.a][cur.b][cur.c]=1;
ans[cur.a][cur.b][cur.c]=0;
que.push(cur);
while(!que.empty())
{
cur=que.front();
que.pop();
get_togo(cur.c);
for(int dir=0;dir<4;dir++)
{
if(togo[dir]==0)continue;
int x=cur.a+dx[dir];
int y=cur.b+dy[dir];
if(x>n||x<1||y>m||y<1)continue;
if(block[x][y]==1)continue;
int new_state=haha[L];
new_state&=(cur.c<<2);
new_state|=OR[dir];
if(ans[x][y][new_state]>ans[cur.a][cur.b][cur.c]+1)
{
ans[x][y][new_state]=ans[cur.a][cur.b][cur.c]+1;
if(x==1&&y==1)return ans[x][y][new_state];
if(!vis[x][y][new_state])
{
vis[x][y][new_state]=1;
que.push(DAT(x,y,new_state));
}
}
}
}
return -1;
}
int main()
{
int cas=1;
while(scanf("%d%d %d",&n,&m,&L)!=EOF)
{
if(n+m+L==0)break;
for1(i,L)read(snake[i][1],snake[i][2]);
int tmp;read(tmp);
mm(block,0);
while(tmp--)
{
int a,b;
read(a,b);
block[a][b]=1;
}
int minn=dfs();
printf("Case %d: %d\n",cas++,minn);
}
}