腾讯马拉松第五场第四题--小明迷藏

题目与代码

//Problem Description
//  小明的妈妈生了三个孩子,老大叫大明, 老二叫二明, 老三..., 老三自然就叫小明了。
//  一天,小明的妈妈带小明兄弟三人去公园玩耍,公园里面树木很多,有很多地方可以藏身, 于是他们决定玩捉迷藏。经过几轮的猜拳后,第一轮是小明来找其他两个人,游戏规则很简单:
//  只要小明可以在规定的时间内找到他们就算小明获胜,并且被发现的两个人猜拳决定谁在下一轮负责找人;如果在规定的时间内只找到一个人,那么没有被发现的人获胜,被找到的人下一轮负责找人;如果在规定的时间内一个人都没有找到,则小明失败了,下一轮还是他来找人。现在小明想知道,在规定时间内,自己是否可以找到所有的人,现在他想请你来帮忙计算一下。
//  为了简单起见,把公园看成是n行m列的矩阵,其中’S’表示小明,’D’表示大名,’E’表示二明,’X’表示障碍物,’.’表示通路。这里,我们把发现定义为,可以直接看到对方, 也就是说两个人在同一行或者同一列,并且中间没有障碍物或者没有其他人就可以看到对方。并且假设,大明,二明藏好以后就不会再改变位置,小明每个单位时间可以从当前的位置走到相邻的四个位置之一,并且不会走出公园。
// 
//
//Input
//测试数据第一行是一个正整数T,表示有T组测试数据。
//每一组测试数据首先是三个正整数n,m,t,分别表示行数、列数和规定的时间,接下来n行,每行m个上述的字符,并且保证有且只有一个’S’,一个’E’,一个’D’。
//
//[Technical Specification]
//T < 200
//3 <= n, m <= 100
//0 <= t <= 100
// 
//
//Output
//每组先输出一行Case c:(c表示当前的组数,从1开始计数);
//接下来一行,如果小明可以在规定时间内找到所有的人,则输出最少需要的时间,否则输出-1。
// 
//
//Sample Input
//3
//5 6 3
//XXD...
//....E.
//....X.
//....S.
//......
//5 6 3
//XDX...
//....E.
//......
//....S.
//......
//5 6 8
//XXDX..
//.XEX..
//......
//....S.
//......
// 
//
//Sample Output
//Case 1:
//-1
//Case 2:
//3
//Case 3:
//-1


#include "stdafx.h"
#include <iostream>
#include <queue>

using namespace std;
#define MAX 110
#define inf 10000
char place[MAX][MAX];
int Searched[MAX][MAX][3];//Searched[x][y][0]到达(x,y)处最早时间(没有看到大明和二明)
int see[2][MAX][MAX];
int m,n,t;
struct Node
{
	int x;
	int y;
	//int dist;//初始化将其设置为很大,表示距离
	int getDE;//1代表看到D没看到E,2代表看到E没看到D,0代表什么没看见,记录已经看到的景象
};
int dir[4][2] = {{0,-1},{0,1},{-1,0},{1,0}};
bool Check(int x,int y)
{
	if(x<1||x>m||y<1||y>n||place[x][y] != '.')//if(x>=1 && x<= m && y>=1 && y<=n && (place[x][y]== '.'||place[x][y] == 'S'))
		return false;
	return true;
}
int BFS(int x,int y)
{
	queue<Node> q;
	Searched[x][y][0] = 0;
	if(see[0][x][y] == 1 && see[1][x][y] == 1)
	{
		return 0;
	}
	else
	{
		Node node;
		node.x = x;
		node.y = y;
		//node.dist = 0;//距离
		node.getDE = 0;//谁也没看到
		q.push(node);
	}
	while(!q.empty())
	{
		Node node = q.front();q.pop();
		int dx = node.x;
		int dy = node.y;
		int tt = node.getDE;//看来是代表看到D还是看到E
		int len = Searched[dx][dy][tt] ;//标记已经搜索过
		//int colour = node.colour;
		if(see[0][dx][dy] == 1)
		{
			if(tt == 2)
				return len;
			tt = 1;
		}
		if(see[1][dx][dy] == 1)
		{
			if(tt == 1)
				return len;
			tt = 2;
		}
		for(int i = 0;i < 4;i++)
		{
			int xx = dx + dir[i][0];int yy = dy + dir[i][1];
			if(Check(xx,yy) && Searched[xx][yy][tt] == -1)//将未探索到的点添加进入
			{
				Node node;
				node.x = xx;node.y = yy;node.getDE = tt;
				q.push(node);
				Searched[xx][yy][tt] = len +1;
			}
		}
	}
	return inf;
}
void Init(int dx,int dy,int k)//找到能看到大明与二明的位置
{
	for(int i =0;i<4;i++)
	{
		int dxx = dx + dir[i][0];
		int dyy = dy + dir[i][1];
		while(Check(dxx,dyy))
		{
			see[k][dxx][dyy] = 1;
			dxx = dxx + dir[i][0];
			dyy = dyy + dir[i][1];
		}
	}
}
int main()
{
	int cases;
	cin>>cases;
	int k = 1;
	while(cases--)
	{
		memset(place,' ',sizeof(place));
		memset(see,-1,sizeof(see));
		memset(Searched,-1,sizeof(Searched));
		cin>>m>>n>>t;
		int x,y;
		int dx,dy;
		int ex,ey;
		for(int i = 1;i<=m;i++)
		{
			for(int j =1;j<=n;j++)
			{
				cin>>place[i][j];
				if(place[i][j] == 'S')
				{
					place[i][j] = '.';
					x = i;
					y = j;
				}
				if(place[i][j] == 'D')
				{
					dx = i;
					dy = j;
				}
				if(place[i][j] == 'E')
				{
					ex = i;
					ey = j;
				}
			}
		}
		Init(dx,dy,0);
		Init(ex,ey,1);
		int time = BFS(x,y);
		if(time > t)
			cout<<"Case "<<k<<":\n"<<"-1"<<endl;
		else
		{
				cout<<"Case "<<k<<":\n";
				cout<<time<<endl;
		}
		k++;
	}
	system("pause");
	return 0;
}

总结与分析

  1. 搜索方法:BFS
  2. 原来自以为正确到AC还需要很长的时间,提交时经常“Time Limit Exceeded”,参照牛人的博客不停得优化,才得以AC
  3. 压入队列的内容越少越好,也就是必须压入队列的内容,我一直尝试把距离压入,可是一直TIME Limit Exceeded,没有办法,只能将dist保存在Searched[x][y][k]数组中,必须得说这样很不方便理解,Searched[x][y][0]代表到达(x,y)处既看不到大明也看不到二明的最短距离,Searched[x][y][1]代表到达(x,y)处看到大明看不到二明的最短距离,Searched[x][y][2]代表到达(x,y)处既看不到大明而能看到二明的最短距离。多压入一个变量看来还是很消耗时间的
  4. 在Check判断的时候,采取或比并更快得到结果,根据短路性
  5. 学会使用dir[4][2]建立上下左右方向,模拟运动
  6. 本题难于想到的一点的是:初始化确定能看到大明和二明的矩阵,see[x][y][k]






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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值