hdu-1072 Nightmare(DFS+剪枝)

来源:互联网 发布:淘宝公司简介怎么写 编辑:程序博客网 时间:2024/06/05 17:53

Nightmare

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9944    Accepted Submission(s): 4838


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
33 32 1 11 1 01 1 34 82 1 1 0 1 1 1 01 0 4 1 1 0 4 11 0 0 0 0 0 0 11 1 1 4 1 1 1 35 81 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-113
题目主要思路是DFS,但直接DFS仅限于数据量小于5 5能用,大一点就会超时,所以需要剪枝。关于剪枝的思路,在代码注释中给出了解释,一些重要的地方也做了注释,对题目的解释基本在代码里,代码如下:
////  main.cpp//  hdu1072////  Created by Morris on 16/7/20.//  Copyright © 2016年 Morris. All rights reserved.//#include <cstdio> #include <climits> #define MAX_SZ 10namespace {    using std::scanf;    using std::printf;}int n, m;int min = INT_MAX - 3;//记录迷宫结构的数组int map[MAX_SZ][MAX_SZ] = { 0 };//记录到点(x, y)的最少步数int step[MAX_SZ][MAX_SZ];//记录到点(x, y)所剩的最多时间int times[MAX_SZ][MAX_SZ];//记录方向的数组,分别代表上、下、左、右int dir[4][2] = { { -1, -0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };void dfs(int x, int y, int len, int cnt);int main(int argc, const char *argv[]){    int t, i, j, k;    int time;    int cnt;    while (~scanf("%d", &t)) {        for (i = 0; i < t; ++i) {            scanf("%d%d", &n, &m);            int sx = 0, sy = 0;            for (j = 0; j < n; ++j) {                for (k = 0; k < m; ++k) {                    step[j][k] = INT_MAX - 3;                    times[j][k] = 0;                    scanf("%d", &map[j][k]);                    if (map[j][k] == 2) {                        sx = j;                        sy = k;                    }                }            }                        time = 6;            cnt = 0;            min = INT_MAX - 3;            dfs(sx, sy, time, cnt);            if (min == INT_MAX - 3) {                printf("-1\n");            }            else {                printf("%d\n", min);            }        }    }    return 0;}void dfs(int x, int y, int time, int cnt){    if (x < 0 || y < 0 || x >= n || y >= m) {        return ;    }    if (time <= 0 || cnt >= min) {        return ;    }    if (map[x][y] == 0) {        return ;    }    if (map[x][y] == 3) {        min = cnt < min ? cnt : min;        return ;    }    if (map[x][y] == 4) {        time = 6;    }        //dfs函数的作用是在不被炸死的情况下,求到点(x, y)所用的最少步数    //如果到当前点(x, y)的步数cnt,大于等于step中记录的前面搜索得到的最少步数,那必须剪掉    //其中步数相等的情况,对于当前点来说,相当于一样的结果,本题求的是最少步数,不是求所有结果,所以剪掉    //另一个限制条件,times中记录了基于前面搜索结果后到达当前点所剩的最多时间,这里用‘&&’    //是考虑到前提条件,人必须不会被炸弹炸死,因为不知道还需要多少步才能走到出口,所以仅凭当前点步数最少    //是没办法知道最终是否能够到达出口,若最终不能到达出口,当前点的结果就是无用的    //所以说需要加上时间上的限制条件来剪枝    if (cnt >= step[x][y] && times[x][y] >= time) {        return ;    }    step[x][y] = cnt;    times[x][y] = time;        int i, tx, ty;    for (i = 0; i < 4; ++i) {        tx = x + dir[i][0];        ty = y + dir[i][1];                dfs(tx, ty, time - 1, cnt + 1);    }}


0 0
原创粉丝点击