nyoj999 师傅又被妖怪抓走了 (预处理+bfs+状态压缩)

题目999

题目信息

执行结果

本题排行

讨论区

师傅又被妖怪抓走了

时间限制:1000 ms | 内存限制:65535 KB

难度:3

描写叙述

话说唐僧复得了孙行者,师徒们一心同体,共诣西方。自宝象国救了公主,承君臣送出城西。沿路饥餐渴饮,悟空便为师傅去化斋。等悟空回来,悟净慌慌张张的对悟空说:“不好了,不好了”,还没等悟净说完,悟空说:“师傅又被妖怪抓走了”,悟净:“NO!” ,悟空一脸茫然。悟净:“师傅和二师兄都被妖怪抓走了”。悟空(晕!

)。

为了防止悟空救人,妖怪先把唐憎和八戒分别藏起来,如果悟空在T分钟之后还没找到人。那必然是被妖怪吃掉了。如果悟空在一个n行m列的矩阵内,悟空在每一分钟能够走到上,下,左,右的当中的一个能够走的位置,每次仅仅能走一步。

我们把发现定义为能够直接看到对方,也就是说两个人在同一行或者同一列,而且中间没有障碍物或者没有其它人就能够看到对方。

输入

有多组測试数据,每组首先是三个正整数n , m (3<=n,m<=100), T,(0<=T<=100) 分别代表行数,列数,规定的时间。接下来n 行,每行 m 个字符。

当中’ S ’ 代表悟空的位置,’ D ’代表师傅位置,’ E ’代表八戒的位置。而且保证都仅仅有一个. ’ X ’代表墙 ,’ . ’代表空地 .

输出

每组先输出一行Case c:(c表示当前的组数。从1開始计数);

接下来一行。假设悟空能够在规定时间内找到两人,则输出最少须要的时间,否则输出-1。

例子输入

5 6 3

XXD...

....E.

....X.

....S.

......

5 6 3

XDX...

....E.

......

....S.

......

5 6 8

XXDX..

.XEX..

......

....S.

......

例子输出

Case 1:

-1

Case 2:

3

Case 3:

-1

这道题让我非常焦灼啊。。。开个玩笑 哈哈

这道题的发现定义为能够直接看到对方。所以是不能走X D E 仅仅能是看到

所以在录入数据的时候 我们就提前做好预处理。

把D E的四个方向 能看到的地方都处理一下

然后就是bfs了 而在这里 我提交了几次 发现都不正确 后来无意中的一个数据启示了我

2 3 1

.S.

DXE

输出-1

2 3 3

.S.

DXE

输出3

聪明的你 看出来了吗?假设我们用通常的vis数组标记走过的路径

,对于第二条測试数据 仅仅会输出-1  由于它不会走回头路 。我又存在侥幸的心理 不用vis数组标记了 发现 果然TLE

然后就是不做了 走在路上还在想 到底在这里该怎么优化 。。。果然 睡觉的时候被我想到了 今天早上一大早 就起来做了。

详细方法是 假设又定义了两个数组visE【x】【y】 visD【x】【y】分别记录在x,y点 是否已经找到过E 或D  。

当某个点已经遍历过

我们再推断当前的visD 和visE和之前的是否一致  假设一致 我们就不用走 假设不一致 证明我们在其他点找到了D或E  如今要回来。

详细看代码把

#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
int n,m;
int t;
int s1,s2;
int d1,d2;
int e1,e2;
int dir[4][2]={1,0,0,1,-1,0,0,-1};
char map[105][105];
bool visD[105][105];
bool visE[105][105];
bool vis[105][105];
struct node
{
	int x,y;
	int step;
	bool isfindD;
	bool isfindE;
	friend bool operator<(node a,node b)
	{
		return a.step>b.step;
	}
};
void prepare(int x,int y,char ch)
{
	char ch2;
	int x2,y2;
	if(ch==‘D‘)
	ch2=‘E‘,x2=e1,y2=e2;
	else
	ch2=‘D‘,x2=d1,y2=d2;
	for(int i=x-1;i>=0;i--)
	{
		if(map[i][y]==‘X‘||i==x2&&y==y2)
		break;
		if(map[i][y]==‘.‘)
		map[i][y]=ch;
		else if(map[i][y]==ch2)
		map[i][y]=‘*‘;
		else if(map[i][y]==‘S‘)
		{
			map[i][y]=ch;
			break;
		}
	}
	for(int i=x+1;i<n;i++)
	{
		if(map[i][y]==‘X‘||i==x2&&y==y2)
		break;
		if(map[i][y]==‘.‘)
		map[i][y]=ch;
		else if(map[i][y]==ch2)
		map[i][y]=‘*‘;
		else if(map[i][y]==‘S‘)
		{
			map[i][y]=ch;
			break;
		}
	}
	for(int i=y+1;i<m;i++)
	{
		if(map[x][i]==‘X‘||x==x2&&i==y2)
		break;
		if(map[x][i]==‘.‘)
		map[x][i]=ch;
		else if(map[x][i]==ch2)
		map[x][i]=‘*‘;
		else if(map[x][i]==‘S‘)
		{
			map[x][i]=ch;
			break;
		}
	}
	for(int i=y-1;i>=0;i--)
	{
		if(map[x][i]==‘X‘||x==x2&&i==y2)
		break;
		if(map[x][i]==‘.‘)
		map[x][i]=ch;
		else if(map[x][i]==ch2)
		map[x][i]=‘*‘;
		else if(map[x][i]==‘S‘)
		{
			map[x][i]=ch;
			break;
		}
	}
}
bool limit(int x,int y)
{
	if(x==d1&&y==d2)
	return false;
	if(x==e1&&y==e2)
	return false;
	if(x<0||y<0||x>=n||y>=m||map[x][y]==‘X‘)
	return false;
	return true;
}
void check_result(node &temp1)
{
	int x=temp1.x;
	int y=temp1.y;
	if(map[x][y]==‘D‘)
	temp1.isfindD=true;
	else if(map[x][y]==‘E‘)
	temp1.isfindE=true;
	else if(map[x][y]==‘*‘)
	temp1.isfindD=temp1.isfindE=true;
}
int bfs(int x1,int y1,int time)
{
	node temp1,temp2;
	priority_queue<node>s;
	while(!s.empty())
	s.pop();
	temp1.x=x1;temp1.y=y1;temp1.step=0;
	temp1.isfindD=temp1.isfindE=false;
	check_result(temp1);
	visE[x1][y1]=temp1.isfindE;
	visD[x1][y1]=temp1.isfindD;
	vis[x1][y1]=true;
	s.push(temp1);
	while(!s.empty())
	{
		temp1=temp2=s.top();
		s.pop();
		if(temp1.step>time)
		return -1;
		if(temp1.isfindD&&temp1.isfindE)
		return temp1.step;
		for(int i=0;i<4;i++)
		{
			int x1=temp1.x+dir[i][0];
			int y1=temp1.y+dir[i][1];
			if(limit(x1,y1)&&(!vis[x1][y1]||!(visE[x1][y1]==temp1.isfindE&&visD[x1][y1]==temp1.isfindD)))
			{
				temp1.x=x1;
				temp1.y=y1;
				temp1.step++;
				check_result(temp1);
				vis[x1][y1]=true;
				visE[x1][y1]=temp1.isfindE;
				visD[x1][y1]=temp1.isfindD;
				s.push(temp1);
				temp1=temp2;
			}
		}
	}
	return -1;
}
int main()
{
	int ncase=1;
	while(~scanf("%d %d %d",&n,&m,&t))
	{
		memset(map,0,sizeof(map));
		for(int i=0;i<n;i++)
		{
			getchar();
			for(int j=0;j<m;j++)
			{
				scanf("%c",&map[i][j]);
				if(map[i][j]==‘S‘)
				{
					s1=i;
					s2=j;
				}
				if(map[i][j]==‘D‘)
				{
					d1=i;
					d2=j;
				}
				if(map[i][j]==‘E‘)
				{
					e1=i;
					e2=j;
				}
			}
		}
		prepare(d1,d2,‘D‘);
		prepare(e1,e2,‘E‘);
		memset(visD,false,sizeof(visD));
		memset(visE,false,sizeof(visE));
		memset(vis,false,sizeof(vis));
		printf("Case %d:\n%d\n",ncase++,bfs(s1,s2,t));
	}
}
时间: 2024-10-21 06:12:48

nyoj999 师傅又被妖怪抓走了 (预处理+bfs+状态压缩)的相关文章

NYOJ999 师傅又被妖怪抓走了

只记得当下的眼疼 , ok 各种数据也试了 , 就是 他娘的不对 , 我也是醉了 . 也是日了最野的狗 附上日了哮天犬的代码 , 这个题 先放放, 一段时间后再试试 , 明天开始状态压缩吧 .为期两天 1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue&g

nyist 999 师傅又被妖怪抓走了 【双广搜 || BFS +状态压缩】

题目:nyist 999 师傅又被妖怪抓走了 分析:在一个图中只要看到D点和E点就行的最小步数,看到的定义是:也就是说两个人在同一行或者同一列,并且中间没有障碍物或者没有其他人就可以看到对方. 所以可以先预处理地图,把D点和E点所在的行列的' .'扩展为d和e,然后只要搜到d和e就可以,问题是只有d和e同时搜到才行,直接广搜肯定不行,我们可以在搜到d点之后然后在从当前点广搜e点,或者e点广搜d点,这样第一次搜到的点不一定是最优的,所以需要枚举所有情况才行,时间复杂度较高. 比较好的一种方法是BF

nyoj 999——师傅又被妖怪抓走了——————【双广搜】

师傅又被妖怪抓走了 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮,悟空便为师傅去化斋,等悟空回来,悟净慌慌张张的对悟空说:“不好了,不好了”,还没等悟净说完,悟空说:“师傅又被妖怪抓走了”,悟净:“NO!” ,悟空一脸茫然,悟净:“师傅和二师兄都被妖怪抓走了”.悟空(晕!).为了防止悟空救人,妖怪先把唐憎和八戒分别藏起来,如果悟空在T分钟之后还没找到人,那必定是被妖怪吃

shu_1548 悟空的难题(大师兄,师傅被妖怪抓走啦!)

http://202.121.199.212/JudgeOnline/problem.php?cid=1078&pid=17 分析:  直接暴力了... 代码: #include <stdio.h> #include <iostream> using namespace std; #define MAXN 2004 #define inf 0x3f3f3f3f int k[MAXN],f[MAXN]; int my_abs(int a) { return a<0? -

openjudge 大师兄,师傅被妖怪抓走啦

描述 孙悟空听到沙僧大喊一句:“大师兄,师傅被妖怪抓走啦!”于是孙悟空直追白骨精而去.孙悟空在一条长度为L的森林小路上飞奔,上面有L+1个整点,依次为0,1,2……L.白骨精会使用一种大范围的攻击法术,产生N个能量球,其中第i个能量球的能量值为f[i],落在小路的整点k[i]上.当孙悟空的位置离能量球i的距离为s时,会受到f[i]-s的伤害,如果f[i]-s计算出的伤害为负值,则判定为0.孙悟空虽然救师心切,但也不能葬身于白骨精的法术之中,因此他想知道应该躲在哪一个整点处,才能让自己受到的总伤害

ACM-康托展开+预处理BFS之魔板——hdu1430

魔板 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1679    Accepted Submission(s): 354 Problem Description 在魔方风靡全球之后不久,Rubik先生发明了它的简化版--魔板.魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示.任一时刻魔板的状态可用方块的颜

Light OJ 1037 - Agent 47(预处理状态压缩DP)

题目大意: 有个特工要执行任务,他会遭遇到最多15个目标,特工必须把他们全部杀死.当他杀死一个目标后他可以使用目标的武器来杀死其他人.因此他必须有一个杀人的顺序,使得他开枪的次数最小. 现在给你一个表,代表每种武器对每个目标可以造成多少伤害.并且你知道每个目标的血量.当这个目标的血量小于等于0的时候说明这个目标被杀死了.最初的时候这个特工只有一个枪,这个枪可以对一个目标造成1点伤害. 题目分析: 先把每个状态下最敌人造成的伤害预处理出来,然后再进行一次记忆化搜索. ===============

HDOJ--3681--Prison Break(BFS预处理+状态压缩DP)

题意 F--起点 S--空格 G--能量池,只能充一次电,充完之后G变为S,也可已选择不充而当成普通的S D--激光区,不能走 Y--电源开关 M被关在一所监狱之中,F为起点,每走一步(上下左右)消耗1节能量,只要关闭完所有的Y就可以直接飞出去,可以到能量池里进行充电.问M要想出去所携带的电池的最小尺寸是多少.注意:能量池和开关的总和小于15. 思路 首先将图中所有的F,G,Y找出来,并用BFS求出这三种标志任意两者的距离.具体看例子 GDDSS SSSFS SYGYS SGSYS SSYSS

【HDOJ3567】【预处理bfs+映射+康拓展开hash】

http://acm.hdu.edu.cn/showproblem.php?pid=3567 Eight II Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 130000/65536 K (Java/Others)Total Submission(s): 4541    Accepted Submission(s): 990 Problem Description Eight-puzzle, which is also calle