Holedox Moving----POJ_1324----BFS+状态压缩

题目地址:http://poj.org/problem?id=1324

Holedox Moving
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 10948 Accepted: 2602

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.

Source

 
题目的大意是就是玩贪吃蛇的游戏,而蛇的蛇身有一个最大长度,为7。每次贪吃蛇在移动的时候,蛇身也跟着一起移动。但是蛇头显然是不能跑到蛇身上去的。题目给你了当前蛇的状态。蛇头以及蛇身的位置,当前地图的信息。为你最快多少步内可以到达(1,1)这个位置。一看觉得是一个很明显的BFS的题目,但是有一点我们要注意的是,这次不是一个地方在动,而是整个蛇身在动,所以这个题目的难点就是对于蛇的状态的记录问题。也就是说判重的问题。看了一些的大牛的博客,学到了一手。在这里我们可以用进制表示蛇的整个状态。因为蛇最长是7个单位。所以我们可以用14个二进制位来表示蛇的状态。每两位表示一个单位长度的状态。分别可以使00,01,10,11这四个状态。我们就用到了vis2[N][N][2<<14]这个数组。其中前两位就是在这个点,而后面那一位就是蛇身的状态了。这个里面还有一个可以优化的问题。那就是我们先把蛇身不管,看蛇头最快要多少min。然后把蛇身看成障碍物,看最慢压多少max。如果min==max的话,那么直接输出就可以了(待证明)。如果最快都不能达到的话,那么我们也可以直接判定蛇不能到达。那么再之后我们再来判断整个蛇的搜索问题了,这个就涉及到了BFS。具体的话就是在BFS中,对蛇身状态的判重。具体细节在这里说不清楚,还是看代码舒服些。
#include<iostream>
#include<queue>
using namespace std;

#define N 22

bool vis1[N][N]; //用来进行判断最快要多少步
bool map[N][N];
bool vis2[N][N][2<<14];
struct point
{
    int x,y;
}p[10];

int len; //用来表示蛇的长度
int n,m;
struct node
{
    int x,y;
    int state;
    int step;
};

int direction[4][2] = {0,1,0,-1,1,0,-1,0};

void setmap()
{
    int i;
    for(i=1;i<len;i++)
    {
        map[p[i].x][p[i].y] = true;     //将此时的蛇身看成障碍物
                                        //这样就不会走到蛇身上去了
    }
}

void clearmap()
{
    int i;
    for(i=1;i<len;i++)
    {
        map[p[i].x][p[i].y] = false;     //将此时的蛇身看成障碍物之后清除掉
                                        //为了下次搜索
    }
}


bool judge1(node no)
{
    if( no.x <1 || no.x > n || no.y < 1 || no.y > m || vis1[no.x][no.y] || map[no.x][no.y])
        return false;
    return true;
}


int bfs1()
{
    memset(vis1,false,sizeof(vis1));
    queue<node> q;
    node start;
    start.x = p[0].x;
    start.y = p[0].y;
    start.step = 0;
    vis1[start.x][start.y] = true;
    q.push(start);

    node cur,next;
    while(!q.empty())
    {
        cur = q.front();
        q.pop();

        if(cur.x == 1 && cur.y == 1)
            return cur.step;
        for(int i=0;i<4;i++)
        {
            next.x = cur.x + direction[i][0];
            next.y = cur.y + direction[i][1];
            if(judge1(next))
            {
                next.step = cur.step+1;
                vis1[next.x][next.y] = true;
                q.push(next);
            }
        }
    }
    return -1;
}

int getmin()
{
    return bfs1();
}

int getmax()
{
    int ret;
    setmap();
    ret = bfs1();
    clearmap();
    return ret;
}

void getpoint(node &a)
{
    p[0].x = a.x;
    p[0].y = a.y;
    int state = a.state;
    int i;
    for(i=1;i<len;i++)
    {
        int d = (state >> ((len - 1 - i)*2)) & 3;   //这里位且3很重要,
                                                    //这样才能把移位之后的最后两位取出来
        p[i].x = p[i-1].x - direction[d][0];
        p[i].y = p[i-1].y - direction[d][1];
    }
}

int getstate()
{
    int state = 0;
    int i,j;
    for(i=1;i<len;i++)
    {
        for(j=0;j<4;j++)
        {
            if(p[i].x == p[i-1].x - direction[j][0] && p[i].y == p[i-1].y - direction[j][1])
            {
                state <<= 2;
                state = state|j;
            }
        }
    }
    return state;
}

bool judge2(node no)
{
    if( no.x <1 || no.x > n || no.y < 1 || no.y > m || vis2[no.x][no.y][no.state] || map[no.x][no.y])
        return false;
    return true;
}


int bfs2()
{
    queue<node> q;
    memset(vis2,false,sizeof(vis2));
    node start;
    start.x = p[0].x;
    start.y = p[0].y;
    start.step = 0;
    start.state = getstate();
    vis2[start.x][start.y][start.state] = true;
    q.push(start);

    node cur,next;
    while(!q.empty())
    {
        cur = q.front();
        q.pop();
        if(cur.x == 1 && cur.y == 1)
            return cur.step;
        getpoint(cur);
        setmap();
        for(int i=0;i<4;i++)
        {
            next.x = cur.x + direction[i][0];
            next.y = cur.y + direction[i][1];
            next.state = cur.state >> 2 | (i<<((len-2)*2));
            if(judge2(next))
            {
                next.step = cur.step+1;
                vis2[next.x][next.y][next.state] = true;
                q.push(next);
            }
        }
        clearmap();
    }
    return -1;
}

int main()
{
    int count = 1;
    while(cin>>n>>m>>len && (n||m||len))
    {
        int i,j;
        memset(map,false,sizeof(map));
        for(i=0;i<len;i++)
        {
            cin>>p[i].x>>p[i].y;
        }
        int t;
        cin>>t;
        int a,b;
        for(i=0;i<t;i++)
        {
            cin>>a>>b;
            map[a][b] = true;
        }
        int ans1,ans2;
        ans1 = getmin();
        ans2 = getmax();
        if(ans1 == -1)
        {
            printf("Case %d: %d\n",count++,ans1);
            continue;
        }
        if(ans1 == ans2)
        {
            printf("Case %d: %d\n",count++,ans1);
            continue;
        }
        ans1 = bfs2();
        printf("Case %d: %d\n",count++,ans1);
    }
    return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值