hdu 1253 胜利大逃亡【BFS】


胜利大逃亡

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 31687    Accepted Submission(s): 11749


Problem Description
Ignatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.

魔王住在一个城堡里,城堡是一个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1.


 

Input
输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后是第1块,第2块......),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙.(如果对输入描述不清楚,可以参考Sample Input中的迷宫描述,它表示的就是上图中的迷宫)

特别注意:本题的测试数据非常大,请使用scanf输入,我不能保证使用cin能不超时.在本OJ上请使用Visual C++提交.
 

Output
对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.
 

Sample Input
 
  
1 3 3 4 20 0 1 1 1 0 0 1 1 0 1 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 0 0 0 0 1 1 0 0 1 1 0
 

Sample Output
 
  
11

题意:略

思路:(BFS)可以用三维数组来解决这题,但是我用的是二维,二维的思路就是,在读入的二维地图中,人在上下左右移动是可以通过x,y轴加减1来实现的,但前后移动就需要加减B来实现,就是单个块矩阵的宽,比如说,第一块的左上角的位置如果想要往前走一步,那么,走到的位置其实是第二块的左上角,在坐标上,就是y轴不变然后x轴向下移动B格。必要的时候还需要做一些剪枝,代码如下:


#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<time.h>
#include<algorithm>
#include<cmath>
#include<stack>
#include<list>
#include<queue>
#include<map>
#define E exp(1)
#define PI acos(-1)
#define mod (ll)(1e9+9)
#define INF 0x3f3f3f3f;
#define MAX 40000
#define compare 0.00000001
#define exps 1e-8
#define fr_add(i,init,n) for(ll i = init ; i < n ; ++i)
#define fr_div(i,init,n) for(ll i = n ; i >= init ; --i)

//#define _CRT_SECURE_NO_WARNINGS
//#define LOCAL
using namespace std;

typedef long long ll;
typedef long double lb;

int p[2510][55], A, B, C, dir[7][2], Time, flag, mark;
struct point {
	int x, y, step;
};


int bfs(struct point tp) {

	queue<struct point> qu;
	struct point temp, Front;

	qu.push(tp);
	flag = 0; mark = 0;

	while (!qu.empty()) {

		Front = qu.front();
		
		fr_add(i, 0, 6) {

			if (Front.x + dir[i][0] >= 0 && Front.x + dir[i][0] < B * A &&
				Front.y + dir[i][1] >= 0 && Front.y + dir[i][1] < C &&
				p[Front.x + dir[i][0]][Front.y + dir[i][1]] == 0) {
				//假设起始点的坐标为 0,0,那么在x轴为B(或B-1)的倍数的时候
				//是不可以直接在存入的地图中向上(或向下)走的,只能左右和前后走
				//在纸上模拟一下就能明白,所以这里有两个条件避开这种情况
				if ((Front.x + 1) % B == 0 && i == 1) continue;
				if ((Front.x) % B == 0 && i == 0) continue;

				p[Front.x + dir[i][0]][Front.y + dir[i][1]] = 1;

				temp.x = Front.x + dir[i][0]; temp.y = Front.y + dir[i][1];
				temp.step = Front.step + 1;
				//如果广搜的到的步数已经大于魔王回来的时间,那么,即使能到门口输出的都是-1
				
				if (temp.step > Time) {
					mark = 1;
					break;
				}

				qu.push(temp);
				if (temp.x == A * B - 1 && temp.y == C - 1) {
					flag = 1;
					break;
				}
			}
		}
		if (flag == 1 || mark == 1) break;
		qu.pop();
	}
	if (flag == 1) return qu.back().step;
	else return -1;
}


int main(void)
{
#ifdef LOCAL
	freopen("data.in.txt", "r", stdin);
	freopen("data.out.txt", "w", stdout);
#endif
	//ios::sync_with_stdio(false); cin.tie(0);
	int t;
	while (scanf("%d", &t) != EOF) {
		while (t--) {
			scanf("%d%d%d%d", &A, &B, &C, &Time);
		// 代码里面的fr_add为宏定义的代码,其实就是一个for循环
			// p二维存取地图
			fr_add(i, 0, A*B) {
				fr_add(j, 0, C) scanf("%d", &p[i][j]);
			}
			struct point start;
			
			// 上下左右前后  为运动的方向
			dir[0][0] = -1; dir[0][1] = 0;
			dir[1][0] = 1; dir[1][1] = 0;
			dir[2][0] = 0; dir[2][1] = -1;
			dir[3][0] = 0; dir[3][1] = 1;
			dir[4][0] = B; dir[4][1] = 0;
			dir[5][0] = -B; dir[5][1] = 0;

			start.step = 0, start.x = 0, start.y = 0;
			p[0][0] = 1;
			int res;
			if (A*B == 1 && C == 1) res = 0;
			//剪枝,从左上角走到右下角的最短途径就是绕着边长宽高的边各走一次
			//假设立方内没有墙,那么走到右下角的最短路径就是A+B+C-3, 如果这个最短路径
			//都要大于魔王回来的时间,那么可以直接输出-1了
			else if (A + B + C - 3 > Time || p[A*B - 1][C - 1] == 1) res = -1;
			else  res = bfs(start);

			printf("%d\n", res);
		}
	}
	//	end = clock();
	//	cout << "using tmie:" << (double)(end - start) / CLOCKS_PER_SEC * (1000) << "ms" << endl;

	//system("pause");
	return 0;
}






猜你喜欢

转载自blog.csdn.net/godleaf/article/details/80193430