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)的更多相关文章

  1. TZOJ 3305 Hero In Maze II(深搜)

    描述 500年前,Jesse是我国最卓越的剑客.他英俊潇洒,而且机智过人^_^.突然有一天,Jesse心爱的公主被魔王困在了一个巨大的迷宫中.Jesse听说这个消息已经是两天以后了,他急忙赶到迷宫,开 ...

  2. 【TOJ 3305】Hero In Maze II

    描述 500年前,Jesse是我国最卓越的剑客.他英俊潇洒,而且机智过人^_^.突然有一天,Jesse心爱的公主被魔王困在了一个巨大的迷宫中.Jesse听说这个消息已经是两天以后了,他急忙赶到迷宫,开 ...

  3. 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 ...

  4. 1006: Hero In Maze

    1006: Hero In Maze 时间限制: 1000 Sec  内存限制: 64 MB提交: 417  解决: 80[提交][状态][讨论版][命题人:外部导入] 题目描述 500年前,Jess ...

  5. Hero In Maze

    Hero In Maze 时间限制(普通/Java):1000MS/10000MS          执行内存限制:65536KByte 描写叙述 500年前,Jesse是我国最卓越的剑客. 他英俊潇 ...

  6. YTU 1006: Hero In Maze

    1006: Hero In Maze 时间限制: 1000 Sec  内存限制: 64 MB 提交: 72  解决: 22 题目描述 500年前,Jesse是我国最卓越的剑客.他英俊潇洒,而且机智过人 ...

  7. ZOJ 649 Rescue(优先队列+bfs)

    Rescue Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  8. 【POJ3635】Full Tank 优先队列BFS

    普通BFS:每个状态只访问一次,第一次入队时即为该状态对应的最优解. 优先队列BFS:每个状态可能被更新多次,入队多次,但是只会扩展一次,每次出队时即为改状态对应的最优解. 且对于优先队列BFS来说, ...

  9. Codeforces 677D - Vanya and Treasure - [DP+优先队列BFS]

    题目链接:http://codeforces.com/problemset/problem/677/D 题意: 有 $n \times m$ 的网格,每个网格上有一个棋子,棋子种类为 $t[i][j] ...

随机推荐

  1. MD5 校验文件

    https://blog.csdn.net/wudishine/article/details/42466831 MD5.h #ifndef MD5_H #define MD5_H #include ...

  2. RS485总线防雷保护方案

    RS485作为最为最常用的电表通讯方式之一.日常生活中雷电和静电干扰已经成为485通信总线在实际工程经常遇到的问题.故如何对芯片以及总线进行有效的保护,是摆在每一个使用者面前的一个问题.在这里,我们主 ...

  3. 通过DBCC整理Sqlserver数据库表索引碎片

    昨天检查了一张效率极慢的表,两年多没有维护,逻辑扫描碎片高达99.%,于是开始对这个表进行重点跟踪和记录日志.今天用DBCC SHOWCONTIG WITH TABLERESULTS 命令检查了一下所 ...

  4. C# 删除文件和目录到回收站

    if (Directory.GetDirectories(projectPath).Length == 0 && Directory.GetFiles(projectPath).Len ...

  5. Vue之vue.js声明式渲染

    Html: <div id="app"> {{ message }} </div> Vue: var app = new Vue({ el: '#app', ...

  6. SVN使用技巧和参考文档总结

    以下文章为网上收集: myEclipse 8.5下SVN环境的搭建(重点推荐) SVN建立版本库,配置用户和权限 Tortoise SVN使用方法,简易图解 版本控制软件SVN使用方法详解 学习笔记 ...

  7. hibernate框架内容整理 学习

    1.1 ORM概述 Object Relation Mapping 对象关系映射. 对象-关系映射(OBJECT/RELATIONALMAPPING,简称ORM),是随着面向对象的软件开发方法发展而产 ...

  8. crontab简易入门

    前言 crontab是Unix和Linux用于设置周期性被执行的指令,是互联网很常用的技术,很多任务都会设置在crontab循环执行,如果不使用crontab,那么任务就是常驻程序,这对你的程序要求比 ...

  9. (转载)Windows无法安装到GPT分区形式磁盘解决办法

    之前使用的是windows7 + ubuntu18.04双系统,硬盘分区采用的是GPT格式.重装windows系统时,提示“windows无法安装到这个磁盘.选中的磁盘采用GPT分区形式”,导致安装失 ...

  10. 实用掌中宝--HTML&CSS常用标签速查手册 PDF扫描版

    实用掌中宝--HTML&CSS常用标签速查手册 内容推荐: 本书第一篇以语法和实例相结合的形式,详细讲解了HTML语言中各个元素及其属性的作用.语法和显示效果:第二篇从CSS基本概念开始,分别 ...