3305: Hero In Maze II (优先队列+bfs)
Description
500年前,Jesse是我国最卓越的剑客。他英俊潇洒,而且机智过人^_^。
突然有一天,Jesse心爱的公主被魔王困在了一个巨大的迷宫中。Jesse听说这个消息已经是两天以后了,他急忙赶到迷宫,开始到处寻找公主的下落。令人头痛的是,Jesse是个没什么方向感的人,因此,他在行走过程中,不能转太多弯了,否则他会晕倒的。 我们假定Jesse和公主所在的位置都是空地,初始时,Jesse所面向的方向未定,他可以选择4个方向的任何一个出发,而不算成一次转弯。希望你帮他判断一下他是否有机会找到心爱的公主。
Input
题目包括多组测试数据.
第1行为一个整数T(1 ≤ T≤ 100),表示测试数据的个数,接下来为T组测试数据.
每组测试数据以两个整数N,M,K(1<=N, M≤100, 0<K<=10)开头,分别代表迷宫的高,长和Jesse最多能转的弯数,(紧接着有N行,M列字符,由".","*","P","S"组成。其中
"." 代表能够行走的空地。
"*" 代表墙壁,Jesse不能从此通过。
"P" 是公主所在的位置。
"S" 是Jesse的起始位置。
每个时间段里Jesse只能选择“上、下、左、右”任意一方向走一步。
Output
如果Jesse能在晕之前找到公主,输出“YES”,否则输出“NO”。
Sample Input
2
5 5 1
P..**
*.**.
S....
.....
*....
5 5 2
P..**
*.**.
S....
.....
*....
Sample Output
NO
YES
http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3305
很久之前就过了这题了,当时是用dfs过的,我也觉得会超时的了,但是提交上去10ms过了,看来还是数据太弱了。必须会超时的,网上其他代码的dfs都会超时,我试过了
40 40 10
P.*.....................................
**......................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
........................................
.......................................S
这样他们的代码就超时了,关于dfs怎么做,应该很容易想的,用dfs(x,y,face,turn)表示在[x,y]那里,面向face那里,转弯次数是turn次的情况,直接dfs即可,唯一的剪枝也就是if (turn>k),就是已经晕了就不行了吧?对于我上面那组数据都超时了,就不用想100*100的矩阵了。
dfs AC代码(不是正解)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (1<<28)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
int flag;
int n,m,k;
const int maxn=1e2+;
char str[maxn][maxn];
int next[][]={{,},{,},{,-},{-,}};
bool book[maxn][maxn];
void dfs (int x,int y,int face,int turn)
{
if (turn>k) return ;//已经晕了就不行了
if (str[x][y]=='P')
{
flag=;//找到公主了
return ;
}
for (int i=;i<;i++)
{
int tx=x+next[i][];
int ty=y+next[i][];
if (!flag&&tx>=&&tx<=n&&ty>=&&ty<=m&&str[tx][ty]!='*'&&book[tx][ty]==)
{
book[tx][ty]=;
if (face!=i)
{
dfs(tx,ty,i,turn+);
}
else dfs(tx,ty,i,turn);
book[tx][ty]=;
}
}
return ;
}
void work ()
{
scanf ("%d%d%d",&n,&m,&k);
for (int i=;i<=n;i++)
{
scanf ("%s",str[i]+);
}
int bx,by;
for (int i=;i<=n;i++)
{
for (int j=;j<=m;j++)
{
if (str[i][j]=='S')
{
bx=i;
by=j;
}
}
}
flag=;
for (int i=;i<;i++)
{
int tx=bx+next[i][];
int ty=by+next[i][];
if (tx>=&&tx<=n&&ty>=&&ty<=m&&str[tx][ty]!='*')
{
memset (book,,sizeof(book));
if (str[tx][ty]=='P')
{
printf ("YES\n");
return ;
}
dfs(tx,ty,i,);
if (flag)
{
printf ("YES\n");
return ;
}
}
}
printf ("NO\n");
return ;
}
int main ()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
int t;
scanf ("%d",&t);
while (t--)
{
work ();
}
return ;
}
这题的正解应该是bfs,我开始的时候,写朴素的bfs无限WA,开始的时候想不出数据,就上网搜,用dfs过了。直到现在,才发现是要用优先队列优化一个bfs,每次pop出当前转弯次数最小的点来转移枚举,这样才能确保答案的最优性。关于怎么证明,我用一组样例来说明,是和本题无关的题目。
题意:大概是这样的,人物P要去救人物S,途中有警察X,没经过一个警察,就要杀死他,耗时+1,其他的,直接一步到达。现在问P-->S的最短时间。
直接用朴素的bfs是会wa的了。这个也应该用优先队列优化。因为bfs是有次序之分的。
.....
p....
.x...
.x...
.S...
明显这组样例输出的是4,但是bfs输出的是6,为什么呢?
首先得看你bfs的反向是怎样的,我的是右--下--左--上。
那么,第一个入队的点,是p右边那个,然后每次扩展的时候,第一个扩展的就是它了,走向了x(3,2),这是没问题的,因为现在走向x的点,步数都是最小的。但是问题来了。走向x(4,2)这个点的会是谁呢?答案是x(3,2),为什么呢?因为它先入队,所以先搜它。照这样下去,走向S的点,就会是x(4,2)了。所以最优性错误。
下面的bfs正解代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (1<<28)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string> int n,m,k;
const int maxn=1e2+;
char str[maxn][maxn];
int next[][]= {{,},{,},{,-},{-,}};
struct coor
{
int x,y,count;
int face;
friend bool operator < (const coor a,const coor b)
{
return a.count>b.count;
}
};
int lbx,lby;
int bfs (int bx,int by,int face)
{
bool book[maxn][maxn]= {};
book[lbx][lby]=;
book[bx][by]=;
priority_queue<struct coor>que;
struct coor t;
struct coor b;
t.x=bx;
t.y=by;
t.count=;
t.face=face;
que.push(t);
while (!que.empty())
{
t=que.top();
que.pop();
if (t.count>k) continue;
for (int i=; i<; i++)
{
b.x=t.x+next[i][];
b.y=t.y+next[i][];
if (b.x>=&&b.x<=n&&b.y>=&&b.y<=m&&str[b.x][b.y]!='*'&&book[b.x][b.y]==)
{
book[b.x][b.y]=;
if (t.face!=i)
{
b.count=t.count+;
}
else b.count=t.count;
b.face=i;
if (str[b.x][b.y]=='P')
{
return b.count;
}
que.push(b);
}
}
}
return inf;
}
void work ()
{
scanf ("%d%d%d",&n,&m,&k);
for (int i=; i<=n; i++)
{
scanf ("%s",str[i]+);
}
for (int i=; i<=n; i++)
{
for (int j=; j<=m; j++)
{
if (str[i][j]=='S')
{
lbx=i;
lby=j;
}
}
}
for (int i=; i<; i++)
{
int tx=lbx+next[i][];
int ty=lby+next[i][];
if (tx>=&&tx<=n&&ty>=&&ty<=m&&str[tx][ty]!='*')
{
if (str[tx][ty]=='P')
{
printf ("YES\n");
return ;
}
int ans=bfs(tx,ty,i);
if (ans<=k)
{
//printf ("%d\n",i);
printf ("YES\n");
return ;
}
//printf ("%d %d\n",ans,i);
}
}
printf ("NO\n");
return ;
} int main ()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
int t;
scanf ("%d",&t);
while (t--)
{
work ();
}
return ;
}
还有我看到有人说这题只能用dfs不能用bfs,那是错误的。希望其他人别用dfs了。用bfs吧。这才是正解。
本人初出茅庐,如果有哪里错误的地方,还请读者多多指出,本人感激不尽!
3305: Hero In Maze II (优先队列+bfs)的更多相关文章
- TZOJ 3305 Hero In Maze II(深搜)
描述 500年前,Jesse是我国最卓越的剑客.他英俊潇洒,而且机智过人^_^.突然有一天,Jesse心爱的公主被魔王困在了一个巨大的迷宫中.Jesse听说这个消息已经是两天以后了,他急忙赶到迷宫,开 ...
- 【TOJ 3305】Hero In Maze II
描述 500年前,Jesse是我国最卓越的剑客.他英俊潇洒,而且机智过人^_^.突然有一天,Jesse心爱的公主被魔王困在了一个巨大的迷宫中.Jesse听说这个消息已经是两天以后了,他急忙赶到迷宫,开 ...
- hdu 1026 Ignatius and the Princess I【优先队列+BFS】
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1026 http://acm.hust.edu.cn/vjudge/contest/view.action ...
- 1006: Hero In Maze
1006: Hero In Maze 时间限制: 1000 Sec 内存限制: 64 MB提交: 417 解决: 80[提交][状态][讨论版][命题人:外部导入] 题目描述 500年前,Jess ...
- Hero In Maze
Hero In Maze 时间限制(普通/Java):1000MS/10000MS 执行内存限制:65536KByte 描写叙述 500年前,Jesse是我国最卓越的剑客. 他英俊潇 ...
- YTU 1006: Hero In Maze
1006: Hero In Maze 时间限制: 1000 Sec 内存限制: 64 MB 提交: 72 解决: 22 题目描述 500年前,Jesse是我国最卓越的剑客.他英俊潇洒,而且机智过人 ...
- ZOJ 649 Rescue(优先队列+bfs)
Rescue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 【POJ3635】Full Tank 优先队列BFS
普通BFS:每个状态只访问一次,第一次入队时即为该状态对应的最优解. 优先队列BFS:每个状态可能被更新多次,入队多次,但是只会扩展一次,每次出队时即为改状态对应的最优解. 且对于优先队列BFS来说, ...
- Codeforces 677D - Vanya and Treasure - [DP+优先队列BFS]
题目链接:http://codeforces.com/problemset/problem/677/D 题意: 有 $n \times m$ 的网格,每个网格上有一个棋子,棋子种类为 $t[i][j] ...
随机推荐
- bzoj 3671 随机数生成器 —— 暴力
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3671 原来256M是可以开两个3e7的数组的: 因为答案只有 n+m-1 个数,所以暴力判断 ...
- ssh免密码登录配置方法,(图示加命令)
首先,说明一下我们要做的是,serverA 服务器的 usera 用户免密码登录 serverB 服务器的 userb用户. 我们先使用usera 登录 serverA 服务器 [root@serve ...
- 不重启linuxVMWare虚拟机添加虚拟磁盘
Vsphere Client找到要添加磁盘的虚机,如图所示 点击虚机右键,在出现的下列列表中选择“编辑设置”如图 在打开的虚拟机属性中,在”硬件对话框点击“添加"按钮,如图 在添 ...
- JavaScript编写代码时候没有提示
如上图所示如果没有提示可能是箭头所指示的类型不正确.
- 问题4:对dict、list、tuple中的元素排序
一)对字典中元素排序 方法一:利用sorted的key参数进行排序 from random import randint date = {k:randint(0, 20) for k in ran ...
- openstackM版本安装
部署期间常见问题:http://www.cnblogs.com/bfmq/p/6001233.html,问题跟对架构的理解永远比部署重要!你玩技术是绝对是要基于理论的 一.基本情况:物理设备:4台惠普 ...
- CSS3新增的伪类
Element1 ~ element2:选择前面有element1的所有element2元素 [attr ^= val] 属性值以val开头的元素 [attr $= val] 属性值以val结尾的元素 ...
- 07_ddms透视图介绍
通过ADB(Android Debug Bridge)安卓调试桥把你的Eclipse(集成开发环境)和你的设备连接在一起.有时候ADB可能会被其他的东西占用.例如WPS会跟你抢ADB(抢端口).如果你 ...
- R中的统计模型
R中的统计模型 这一部分假定读者已经对统计方法,特别是回归分析和方差分析有一定的了解.后面我们还会假定读者对广义线性模型和非线性模型也有所了解.R已经很好地定义了统计模型拟合中的一些前提条件,因此我们 ...
- git中避免提交.DS_Store文件[转载]
1. 先删除原有的.DS_Store: find . -name .DS_Store -print0 | xargs -0 git rm -f --ignore-unmatch 命令解释:在当前文件夹 ...