HDU 1072 Nightmare (BFS)

Nightmare

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 17   Accepted Submission(s) : 4

Font: Times New Roman | Verdana | Georgia

Font Size:

Problem Description

Ignatius had a nightmare last night. He found himself in a labyrinth with a time bomb on him. The labyrinth has an exit, Ignatius should get out of the labyrinth before the bomb explodes. The initial exploding time of the bomb is set to 6 minutes. To prevent the bomb from exploding by shake, Ignatius had to move slowly, that is to move from one area to the nearest area(that is, if Ignatius stands on (x,y) now, he could only on (x+1,y), (x-1,y), (x,y+1), or (x,y-1) in the next minute) takes him 1 minute. Some area in the labyrinth contains a Bomb-Reset-Equipment. They could reset the exploding time to 6 minutes.

Given the layout of the labyrinth and Ignatius' start position, please tell Ignatius whether he could get out of the labyrinth, if he could, output the minimum time that he has to use to find the exit of the labyrinth, else output -1.

Here are some rules:
1. We can assume the labyrinth is a 2 array.
2. Each minute, Ignatius could only get to one of the nearest area, and he should not walk out of the border, of course he could not walk on a wall, too.
3. If Ignatius get to the exit when the exploding time turns to 0, he can't get out of the labyrinth.
4. If Ignatius get to the area which contains Bomb-Rest-Equipment when the exploding time turns to 0, he can't use the equipment to reset the bomb.
5. A Bomb-Reset-Equipment can be used as many times as you wish, if it is needed, Ignatius can get to any areas in the labyrinth as many times as you wish.
6. The time to reset the exploding time can be ignore, in other words, if Ignatius get to an area which contain Bomb-Rest-Equipment, and the exploding time is larger than 0, the exploding time would be reset to 6.

Input

The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case starts with two integers N and M(1<=N,Mm=8) which indicate the size of the labyrinth. Then N lines follow, each line contains M integers. The array indicates the layout of the labyrinth.
There are five integers which indicate the different type of area in the labyrinth:
0: The area is a wall, Ignatius should not walk on it.
1: The area contains nothing, Ignatius can walk on it.
2: Ignatius' start position, Ignatius starts his escape from this position.
3: The exit of the labyrinth, Ignatius' target position.
4: The area contains a Bomb-Reset-Equipment, Ignatius can delay the exploding time by walking to these areas.

Output

For each test case, if Ignatius can get out of the labyrinth, you should output the minimum time he needs, else you should just output -1.

Sample Input

3
3 3
2 1 1
1 1 0
1 1 3
4 8
2 1 1 0 1 1 1 0
1 0 4 1 1 0 4 1
1 0 0 0 0 0 0 1
1 1 1 4 1 1 1 3
5 8
1 2 1 1 1 1 1 4 
1 0 0 0 1 0 0 1 
1 4 1 0 1 1 0 1 
1 0 0 0 0 3 0 1 
1 1 4 1 1 1 1 1 

Sample Output

4
-1
13


代碼:0MS
首先要找最短路就要用的廣搜。
只能保證代碼的正確性,思路懂一點,但是換另一種方法做,就一直WA...
這道題和平時搜索題不同在於有炸彈時間重置點,所以並不是走過的點就不能再走,樣例3就很好的說明了這一點。
這就有一個問題了:怎麼判斷下一個點能不能走,因爲不能再用走過就標記的方法去判斷了。
一些人是判斷重置點只能去一次(明顯,再去時間也只能將時間重置爲6,而路徑加長)。
但是我感覺還是存在在兩個點之間跳,浪費時間的情況,所以我另外開了一個時間二維數組,如果在之後又要回到已經走過的點,
我就判斷剩餘時間是否比之前的大,廣搜已經得出之前到的一定路徑更短,要回到走過的點,一定要在之後可以走更遠,否則回
到該點一定不是最優的情況。於是判斷語句出來了:if(temp.time>T[temp.x][temp.y]) 就可以入隊。
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
using namespace std;
int map[20][20],Time[20][20];
int lx,ly,n,m;
int dis[4][2]={1,0,0,1,-1,0,0,-1};
struct node {
int x,y,time,run;                   //分別是:橫座標,縱座標,剩餘時間,走的步數。
};
int BFS(int fx,int fy,int time,int run)
{
    int i,j;
    node t,temp;
    t.x=fx;t.y=fy;t.time=time;t.run=run;   
    queue<node>Q;                               //起點入隊。    Q.push(t);
    memset(Time,0,sizeof(Time));                //時間表清空。
    Time[t.x][t.y]=t.time;                      //起點的剩餘時間當然是6.
    while(!Q.empty())
    {
      t=Q.front();
      Q.pop();
      if(t.time==0) continue;                  //因爲時間一到0炸彈就炸了,就算剛好到終點或重置點也炸了。所以就不用再去處理了。
      else
      {
      if(map[t.x][t.y]==4) t.time=6;          //如果到4,時間重置爲6.
      if(t.x==lx && t.y==ly)
      {
        return  t.run;                        // 到達終點返回步數,廣搜最先到的一定是步數最少的。
      }

          for(i=0;i<4;i++)                   //向四個方向走。
          {
            temp.x=t.x+dis[i][0];
            temp.y=t.y+dis[i][1];
            temp.time=t.time-1;
            temp.run=t.run+1;
            if( temp.x>=0 && temp.x<n && temp.y>=0 && temp.y<m && map[temp.x][temp.y]!=0)  //判斷是否可以走。
                   if(temp.time>Time[temp.x][temp.y])                                      //沒走過,當然成立;如果走過,就像上面說的,判斷是否會出現
              {                                                                            //更優解的可能。
                   Time[temp.x][temp.y]=temp.time;                                         //對時間表更新。理由同上。
                   Q.push(temp);
              }
          }
       }
      }
        return -1;
    }
int main()
{
    int t,i,j;
    int fx,fy;
    while(scanf("%d",&t)!=EOF)
    {
        while(t--)
        {
            memset(map,0,sizeof(map));
            scanf("%d%d",&n,&m);
            for(i=0;i<n;i++)
                for(j=0;j<m;j++)
            {
                scanf("%d",&map[i][j]);
                if(map[i][j]==2) {fx=i;fy=j;}                  //找起點。
                if(map[i][j]==3) {lx=i;ly=j;}                  //找終點。
            }
            i=BFS(fx,fy,6,0);                                 
            printf("%d\n",i);
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章