//poj 1324 Holedox Moving 贪食蛇(bfs+剪枝)
/*
题解:http://blog.sina.com.cn/s/blog_520db5ec0100coqb.html
上面这位哥们的题解够详细了,运用了他的那个剪枝就不会超时(近1000MS).
PS: 广搜+剪枝的题是最让我头疼的题,这道题搞了一个下午。
剪枝的灵感一般都来源于题目本身的特殊性,这道贪食蛇的
剪枝也是运用了食运用的特征,非常巧妙。
*/
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int inf = 1<<30;
int n,m,k;
int move[4][2]={-1,0,0,1,1,0,0,-1};
int Min,Max;
int stone[21][21];
struct node
{
int x,y,c,d; //c表示步数,d表示蛇尾状态(压缩)
};
struct P
{
int x,y,c;
};
bool mark[21][21][16400];
//用头的坐标和蛇尾的状态保存,20*20*(4^7)
//蛇尾的状态就是7个点分别相对于前面一点的
//方向,有4个,每一个方向用两位表示
//计算最小最大值用于剪枝
void init(int &ans,int v,int w)
{
bool visit[21][21]={false};
visit[v][w]=true;
queue<P> Q;
P tmp,t;
tmp.x=v,tmp.y=w,tmp.c=0;
Q.push(tmp);
while (!Q.empty())
{
tmp=Q.front();Q.pop();
if (tmp.x==1 && tmp.y==1) { ans=tmp.c; return ;}
++tmp.c;
for (int i=0;i<4;i++)
{
tmp.x+=move[i][0],tmp.y+=move[i][1];
if (tmp.x>=1 && tmp.x<=n && tmp.y>=1 && tmp.y<=m && !stone[tmp.x][tmp.y] && !visit[tmp.x][tmp.y])
{
visit[tmp.x][tmp.y]=true;
Q.push(tmp);
}
tmp.x-=move[i][0],tmp.y-=move[i][1];
}
}
ans=inf;
}
int bfs(node &s)
{
memset(mark,false,sizeof(mark));
mark[s.x][s.y][s.d]=true;
int h,x,y,j,l;
queue<node> Q;
Q.push(s);
node t,tmp;
while (!Q.empty())
{
tmp=Q.front();Q.pop();
if (tmp.x==1 && tmp.y==1) return tmp.c;
if (tmp.c+tmp.y+tmp.x-2>Max) continue; //剪枝2
for (int i=0;i<4;i++)
{
t.x=tmp.x+move[i][0],t.y=tmp.y+move[i][1];
if (t.x>=1 && t.x<=n && t.y>=1 && t.y<=m && !stone[t.x][t.y])
{
x=tmp.x,y=tmp.y;
for (j=0;j<k-1;j++)
{
l=(tmp.d>>(j<<1))&3;
x+=move[l][0],y+=move[l][1];
if (t.x==x && t.y==y) break;
}
if (j<k-1) continue;
t.d=( (tmp.d&((1<<((k-2)<<1))-1))<<2 )|((i+2)%4);
if (!mark[t.x][t.y][t.d])
{
mark[t.x][t.y][t.d]=true;
t.c=tmp.c+1;
Q.push(t);
}
}
}
}
return -1;
}
int main()
{
int tm=0;
while (scanf("%d%d%d",&n,&m,&k) && n+m+k)
{
memset(stone,0,sizeof(stone));
int a,b,num,l;
node s;
scanf("%d%d",&s.x,&s.y);
int px=s.x,py=s.y;
s.d=0;
for (int i=0;i<k-1;i++) {
scanf("%d%d",&a,&b);
for (int j=0;j<4;j++)
{
if (px+move[j][0]==a && py+move[j][1]==b)
{
s.d|=j<<(i<<1);
px=a,py=b;
break;
}
}
}
scanf("%d",&num);
while (num--){
scanf("%d%d",&a,&b);
stone[a][b]=1;
}
s.c=0;
init(Min,s.x,s.y);
if (Min==inf) { //剪枝1
printf("Case %d: %d/n",++tm,-1);
continue;
}
//把蛇尾当作石头,算出最多的步数,答案就在[Min,Max]之间
px=s.x,py=s.y;
for (int i=0;i<k-1;i++)
{
l=(s.d>>(i<<1))&3;
px+=move[l][0],py+=move[l][1];
stone[px][py]=1;
}
init(Max,s.x,s.y);
if (Min==Max) {
printf("Case %d: %d/n",++tm,Min);
continue;
}
//还原
stone[px][py]=0;
for (int i=k-2;i>=1;i--)
{
l=(s.d>>(i<<1))&3;
px-=move[l][0],py-=move[l][1];
stone[px][py]=0;
}
printf("Case %d: %d/n",++tm,bfs(s));
}
system("pause");
return 0;
}
/*
5 6 2
5 1
4 1
3
2 3
3 3
3 4
*/