首页 > 代码库 > HDU2128Tempter of the Bone II(bfs+状态压缩)

HDU2128Tempter of the Bone II(bfs+状态压缩)

Tempter of the Bone II

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 98304/32768 K (Java/Others)
Total Submission(s): 1529    Accepted Submission(s): 407


Problem Description
The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze was changed and the way he came in was lost.He realized that the bone was a trap, and he tried desperately to get out of this maze.


The maze was a rectangle with the sizes of N by M. The maze is made up of a door,many walls and many explosives. Doggie need to reach the door to escape from the tempter. In every second, he could move one block to one of the upper, lower, left or right neighboring blocks. And if the destination is a wall, Doggie need another second explode and a explosive to explode it if he had some explosives. Once he entered a block with explosives,he can take away all of the explosives. Can the poor doggie survive? Please help him.
 

Input
The input consists of multiple test cases. The first line of each test case contains two integers N, M,(2 <= N, M <= 8). which denote the sizes of the maze.The next N lines give the maze layout, with each line containing M characters. A character is one of the following:

‘X‘: a block of wall;
‘S‘: the start point of the doggie;
‘D‘: the Door;
‘.‘: an empty block;
‘1‘--‘9‘:explosives in that block.

Note,initially he had no explosives.

The input is terminated with two 0‘s. This test case is not to be processed.
 

Output
For each test case, print the minimum time the doggie need to escape if the doggie can survive, or -1 otherwise.
 

Sample Input
4 4 SX.. XX.. .... 1..D 4 4 S.X1 .... ..XX ..XD 0 0
 

Sample Output
-1 9
 

Author
XHD
 

Source
HDU 2007-10 Programming Contest
 

题意:要求从 S 点走到 D 点的最短时间,‘1’~‘9’:表示当前位置有炸药数量,X:表示墙。" . ":表示可走的路。墙可以用一包炸药炸通,需花一个单位时间。

分析:从S到D,所经过的每个位置得到的炸药数量可能不等,就算得到的炸药数量相等,但每个到达当前位置时的地图的状态不同。所以我们不仅必须判断在每个位置得到的炸药数是否存在过,而且还要判断得到的这些炸药数在相同情况下不同地图的状态。

#include<stdio.h>
#include<iostream>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;

struct State
{
    short state[8];//地图每行压缩的状态,
};
struct node
{
    int x,y; //当前走到的位置
    int time,explosiveNumb; //走过的时间,得到的炸药数量
    State s;  //走过后的地图状态
    friend bool operator<(const node &a,const node &b) //优先队列以时间最小的顺序取
    {
        return a.time>b.time;
    }
};

int n,m;
char map[10][10];
vector<State>vist[8][8][560]; //走到地图每个位置得到不同炸药数量的地图状态有没有存在过

void init()
{
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        for(int k=0; k<559; k++)
        vist[i][j][k].clear();
}
bool judge(int x,int y,int numb,short state[])
{
    int length=vist[x][y][numb].size();
    for(int i = 0; i < length ;i++)
    {
        int j;
        for(j = 0; j<n ; j++)
            if(vist[x][y][numb][i].state[j]!=state[j])
            break;
        if(j==n) //当前将要走的state[]地图状态,不必再加入队列(即己经存在过)
            return false;
    }
    //当前将要走的地图状态没存在过,需加入队列
    return true;
}
int bfs(int sx,int sy)
{
    int dir[4][2]={0,1,0,-1,1,0,-1,0};
    priority_queue<node>q;
    node p,tp;

    init();
    p.x=sx;
    p.y=sy;
    p.time=0;
    p.explosiveNumb=0;
    for(int i=0;i<n;i++)
    {
        p.s.state[i]=0;
        //压缩每行地图的状态,位置是 1 表示不存在任何东西
        for(int j=0;j<m;j++)
            if(map[i][j]=='.')
        p.s.state[i]|=(1<<j);
    }
    
    vist[sx][sy][0].push_back(p.s);
    q.push(p);
    while(!q.empty())
    {
        p=q.top();
        q.pop();
        for(int e=0;e<4;e++)
        {
            tp=p;
            tp.x+=dir[e][0];
            tp.y+=dir[e][1];
            tp.time++;
            if(tp.x>=0&&tp.x<n&&tp.y>=0&&tp.y<m)
            {
                if(!(tp.s.state[tp.x]&(1<<tp.y))&&map[tp.x][tp.y]=='X'&&!tp.explosiveNumb) //表示将要走的位置是现在还没炸的墙,并且身上没有炸药
                    continue ;
                if(!(tp.s.state[tp.x]&(1<<tp.y))&&map[tp.x][tp.y]>'0'&&map[tp.x][tp.y]<='9') //表示将要走的位置是没有取走的炸药
                {
                    tp.explosiveNumb+=map[tp.x][tp.y]-'0';
                    tp.s.state[tp.x]|=1<<tp.y; //取走后变成 "."
                }
                else if(!(tp.s.state[tp.x]&(1<<tp.y))&&map[tp.x][tp.y]=='X'&&tp.explosiveNumb)  //表示将要走的位置是现在还没炸的墙,身上有炸药
                {
                    tp.explosiveNumb--;
                    tp.s.state[tp.x]|=1<<tp.y; //炸完后变成 "."
                    tp.time++;
                }
                else if(map[tp.x][tp.y]=='D')
                    return tp.time;
                if(judge(tp.x,tp.y,tp.explosiveNumb,tp.s.state)) //判断走到当前位置的炸药数量与地图状态是否没有存在过?为真没存在过,否则为存在过
                vist[tp.x][tp.y][tp.explosiveNumb].push_back(tp.s),q.push(tp);
            }
        }
    }
    return -1;
}
int main()
{
    int sx,sy;
    while(scanf("%d%d",&n,&m)>0)
    {
        if(n==0&&m==0)
            break;
        for(int i=0;i<n;i++)
            scanf("%s",map[i]);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            if(map[i][j]=='S')
            sx=i,sy=j;
        printf("%d\n",bfs(sx,sy));
    }
}


HDU2128Tempter of the Bone II(bfs+状态压缩)