poj 1324 Holedox Moving

来源:互联网 发布:p2p网络金融 编辑:程序博客网 时间:2024/06/06 09:04


 
//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

*/