poj 1324 Holedox Moving

Holedox Moving
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 13428 Accepted: 3190

Description

During winter, the most hungry and severe time, Holedox sleeps in its lair. When spring comes, Holedox wakes up, moves to the exit of its lair, comes out, and begins its new life. 
Holedox is a special snake, but its body is not very long. Its lair is like a maze and can be imagined as a rectangle with n*m squares. Each square is either a stone or a vacant place, and only vacant places allow Holedox to move in. Using ordered pair of row and column number of the lair, the square of exit located at (1,1). 

Holedox's body, whose length is L, can be represented block by block. And let B1(r1,c1) B2(r2,c2) .. BL(rL,cL) denote its L length body, where Bi is adjacent to Bi+1 in the lair for 1 <= i <=L-1, and B1 is its head, BL is its tail. 

To move in the lair, Holedox chooses an adjacent vacant square of its head, which is neither a stone nor occupied by its body. Then it moves the head into the vacant square, and at the same time, each other block of its body is moved into the square occupied by the corresponding previous block. 

For example, in the Figure 2, at the beginning the body of Holedox can be represented as B1(4,1) B2(4,2) B3(3,2)B4(3,1). During the next step, observing that B1'(5,1) is the only square that the head can be moved into, Holedox moves its head into B1'(5,1), then moves B2 into B1, B3 into B2, and B4 into B3. Thus after one step, the body of Holedox locates in B1(5,1)B2(4,1)B3(4,2) B4(3,2) (see the Figure 3). 

Given the map of the lair and the original location of each block of Holedox's body, your task is to write a program to tell the minimal number of steps that Holedox has to take to move its head to reach the square of exit (1,1). 

Input

The input consists of several test cases. The first line of each case contains three integers n, m (1<=n, m<=20) and L (2<=L<=8), representing the number of rows in the lair, the number of columns in the lair and the body length of Holedox, respectively. The next L lines contain a pair of row and column number each, indicating the original position of each block of Holedox's body, from B1(r1,c1) to BL(rL,cL) orderly, where 1<=ri<=n, and 1<=ci<=m,1<=i<=L. The next line contains an integer K, representing the number of squares of stones in the lair. The following K lines contain a pair of row and column number each, indicating the location of each square of stone. Then a blank line follows to separate the cases. 

The input is terminated by a line with three zeros. 

Note: Bi is always adjacent to Bi+1 (1<=i<=L-1) and exit square (1,1) will never be a stone. 

Output

For each test case output one line containing the test case number followed by the minimal number of steps Holedox has to take. "-1" means no solution for that case.

Sample Input

5 6 4
4 1
4 2
3 2
3 1
3
2 3
3 3
3 4

4 4 4
2 3
1 3
1 4
2 4
4

2 1
2 2
3 4
4 2

0 0 0

Sample Output

Case 1: 9
Case 2: -1

Hint

In the above sample case, the head of Holedox can follows (4,1)->(5,1)->(5,2)->(5,3)->(4,3)->(4,2)->(4,1)->(3,1)->(2,1)->(1,1) to reach the square of exit with minimal number of step, which is nine. 

此题巨坑啊,写+调试好几个小时,一直被那个上下左右搞得头晕。

废话不多说,来说说此题的解法。很显然此题的蛇是有长度的,那么光记录一个蛇头是不行的,必须记录蛇身,因为这题加了蛇的长度限制L<=8,因此可以开个多维数组记录,这里为了怕麻烦,就直接HASH了,用0,1,2,3分别某节蛇身和前一节蛇身的关系,我在程序里已经标注,因此最多7节蛇身,用14位2进制数表示即可。

这题的算法显然也是BFS,那么一个状态如何转移呢?我用了点技巧,首先我14位2进制的排布是精心设计了一下,最低2位表示的是第1节蛇身和蛇头的关系,因此最高2位才是最后1节蛇身和最后第2节蛇身的关系,这样的话有个好处,只要根据蛇头的坐标,从14位2进制数的低2位开始,可以依次得到各节蛇身的坐标,这样看起来也比较自然。然后搜索的数组也不是随便排的,满足上+下=3,左+右=3,并且蛇身坐标关系和这个刚好相反,

也就是dx[0],dy[0]表示向右搜索,那么0表示蛇身的关系为下一节在前一节的左边,为什么这么搞呢?

因为我们发现一个状态装移到另外一个状态,其实关系变化不多,只是稍微移动了一下。比如之前蛇身关系右左右,如果此时蛇头往下移,当然第二节蛇身肯定在蛇头上方了,之后呢?第三节替代第二节,第四节替代第三节。。。,也就是后面的二进制序列往后移了两位,在加上蛇头移动的反方向,就构成了新状态。

但巧妙的是,我设计的状态蛇尾是高位,第一节蛇身在最低2位,因此变为左移2位+蛇头反方向,注意去掉移除高位的2位,舒服多了吧!

更巧妙地是,我之前还说了搜索方向和蛇身关系相反,那么蛇头反方向不就变成搜索方向了,这下直接+i即可了。那么在根据14位二进制和蛇头位置算蛇身坐标时(蛇头不可以往蛇身占据的坐标搜索),从低二位开始,记得刚才说了搜索方向和蛇身关系相反,如果是上,那得改成下,左得改成右,再看上面:上+下=3,左+右=3,这下爽了,直接3减一下。。。

所以说吧,一道题目仔细思考状态,花点心思用些技巧去表示,会使题目变得简单。


代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

struct snake{
    int x,y,pos,step;
    snake(){}
    snake(int tx,int ty,int tpos,int st):x(tx),y(ty),pos(tpos),step(st){}
}s,q[6554000];
struct node{
    int x,y;
    node(){}
    node(int tx,int ty):x(tx),y(ty){}
}p[10];
int n,m,l,base;
int dx[]={0,1,-1,0}; //右下上左
int dy[]={1,0,0,-1};
int vis[21][21][1<<14];
int maze[21][21];
int get_pos(int a,int b,int x,int y){
    x-=a,y-=b;
    if(y==-1) return 0; //左
    if(y==1) return 3; //右
    if(x==-1) return 1; //上
    return 2; //下
}
bool judge(int x,int y,int tot){
    for(int i=0;i<tot;i++)
        if(p[i].x==x&&p[i].y==y) return true;
    return false;
}
int bfs(snake &k){
    int s=0,e=-1;
    q[++e]=k;
    while(s<=e){
        snake t=q[s++];
        if(t.x==1&&t.y==1) return t.step;
        for(int i=0;i<4;i++){
            int tx=t.x+dx[i],ty=t.y+dy[i],tpos=t.pos<<2&base|i,tp=t.step+1;
            if(tx<1||ty<1||tx>n||ty>m||vis[tx][ty][tpos]||maze[tx][ty]) continue;
            int tot=0,a=t.x,b=t.y,tmp=t.pos;
            for(int j=0;j<l;j++){
                int cur=3-(tmp&3);
                tmp>>=2;
                p[tot++]=node(a+=dx[cur],b+=dy[cur]);
            }
            if(judge(tx,ty,tot)) continue;
            q[++e]=snake(tx,ty,tpos,tp);
            vis[tx][ty][tpos]=1;
        }
    }
    return -1;
}
int main()
{
    int x,y,cas=1,a,b,k;
    while(scanf("%d%d%d",&n,&m,&l),n){
        scanf("%d%d",&a,&b);
        s.x=a,s.y=b,s.pos=0,s.step=0;
        l--;
        base=0;
        for(int i=0;i<(l<<1);i++) base=base<<1|1;
        for(int i=0;i<l;i++){
            scanf("%d%d",&x,&y);
            s.pos=s.pos|get_pos(a,b,x,y)<<(i<<1); //蛇尾高位
            a=x,b=y;
        }
        scanf("%d",&k);
        memset(maze,0,sizeof maze);
        memset(vis,0,sizeof vis);
        while(k--){
            scanf("%d%d",&a,&b);
            maze[a][b]=1;
        }
        printf("Case %d: %d\n",cas++,bfs(s));
    }
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值