题目大意:给你一张有n * m个网格的图,每个网格可能是如下符号:

“#”:墙

“P”:出发点

“D”:终点

“.”:空地

“*”:传送机

有一个旅行家(假设名叫Mike),他要从点P到达点D,途中必须遵循如下规则:

1、  Mike可以走到空地(“.”),但不可通过墙(“#”)。

2、  Mike也可以走到传送机(“*”),但是当他第一次到达传送机时,下一步只有一种选择:他必须选择到达另一个传送机,然后,下一步会有两种选择:

一、走到相邻的可去的格子中。

二、选择到达另一个传送机,然后遵循同样的规则。

让你计算出Mike从点P到点D的最少步数,如果不能到达,就输出“impossible”。

解题思路:Mike从点P到达点D只可能有两种方式:

1、  经过传送机(“*”), 但图中必须有两个或两个以上的传送机。

2、  不经过传送机,只经过空地(“.”)。

所以只需找出两种方式所需步数的最小值即可。

Ps:程序后面有几组我自己的测试样例,请仔细理解。

具体解法请看程序:

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define PI acos(-1.0)
#define inf 0x3fffffff
#define mem(a,b) memset(a,b,sizeof(a)) using namespace std;
const int MAXN = 205 ;
char s[MAXN][MAXN] ;
bool vis[MAXN][MAXN] ;
int dP[MAXN][MAXN] ; // 记录点P到每个点网格中每个点(中间不经过“*”)的最短距离
int dD[MAXN][MAXN] ; // 记录点D到每个点网格中每个点(中间不经过“*”)的最短距离
int ci[MAXN][MAXN] ; // 记录每个“*”点是否能从点P或点D到达。
int ca ;
int m , n ;
int te ; // 统计矩阵中的 “*” 数量。
int X[4] = {0 , 0 , 1 , -1} ; // 四个方向
int Y[4] = {1 , -1 , 0 , 0} ;
int MIN ; // 记录从点P 到 点D 距离的最小值
struct Node
{
int x ;
int y ;
};
Node c , e ; // c代表点P ,e 代表 点D struct Kx // 记录 每个可达的 “*”到点P 和 到点D的最近距离
{
int x ;
int y ;
int d ;
} kkP[MAXN * MAXN] , kkD[MAXN * MAXN] ;
int cntP , cntD ;
void init() // 输入
{
scanf("%d%d" , &m , &n) ;
mem(ci , 0) ;
int i , j ;
te = 0 ;
for(i = 0 ; i < m ; i ++)
{
scanf("%s" , s[i]) ;
for(j = 0 ; j < n ; j ++)
{
if(s[i][j] == '*')
{
te ++ ;
}
else if(s[i][j] == 'P')
{
c.x = i ;
c.y = j ;
}
else if(s[i][j] == 'D')
{
e.x = i ;
e.y = j ;
}
}
}
}
queue<Node> q ;
int cango1(int x , int y)
{
if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && ((s[x][y] == '.' || s[x][y] == 'D')))
return 1 ;
return 0 ;
}
int cango2(int x , int y)
{
if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && s[x][y] != '#')
return 1 ;
return 0 ;
}
bool flag ; // 判断点P是否能不经过点 “*” 到达 点D 。
void bfs(int i , int j , int bb) // 从点P bfs
{
while (!q.empty()) q.pop() ;
Node tmp ;
tmp.x = i ;
tmp.y = j ;
q.push(tmp) ;
vis[i][j] = true ;
while (!q.empty())
{
tmp = q.front() ;
q.pop() ;
int k ;
int tx , ty ;
for(k = 0 ; k < 4 ; k ++)
{
Node tp2 ;
tx = tmp.x + X[k] ;
ty = tmp.y + Y[k] ;
if(bb == 1)
{
if(cango1(tx , ty))
{
dP[tx][ty] = dP[tmp.x][tmp.y] + 1 ;
if(tx == e.x && ty == e.y)
flag = true ;
vis[tx][ty] = true ;
tp2.x = tx ;
tp2.y = ty ;
q.push(tp2) ;
}
}
else
{
if(cango2(tx , ty))
{
dP[tx][ty] = dP[tmp.x][tmp.y] + 1 ;
if(s[tx][ty] == '*')
{
ci[tx][ty] ++ ;
++ cntP ;
kkP[cntP].x = tx ;
kkP[cntP].y = ty ;
kkP[cntP].d = dP[tx][ty] ;
}
if(tx == e.x && ty == e.y)
flag = true ;
vis[tx][ty] = true ;
tp2.x = tx ;
tp2.y = ty ;
if(s[tx][ty] != '*') // 注意此处
q.push(tp2) ;
}
}
}
}
}
void bfs2(int i , int j ) // 从点D bfs
{
while (!q.empty()) q.pop() ;
Node tmp ;
tmp.x = i ;
tmp.y = j ;
q.push(tmp) ;
vis[i][j] = true ;
while (!q.empty())
{
tmp = q.front() ;
q.pop() ;
int k ;
int tx , ty ;
for(k = 0 ; k < 4 ; k ++)
{
Node tp2 ;
tx = tmp.x + X[k] ;
ty = tmp.y + Y[k] ;
if(cango2(tx , ty))
{
dD[tx][ty] = dD[tmp.x][tmp.y] + 1 ;
if(s[tx][ty] == '*')
{
ci[tx][ty] ++ ;
++ cntD ;
kkD[cntD].x = tx ;
kkD[cntD].y = ty ;
kkD[cntD].d = dD[tx][ty] ;
}
vis[tx][ty] = true ;
tp2.x = tx ;
tp2.y = ty ;
if(s[tx][ty] != '*') // 注意此处
q.push(tp2) ;
}
}
}
} void solve()
{
printf("Case %d: " , ++ ca) ;
flag = false ;
mem(dP , 0) ;
mem(dD , 0) ;
mem(vis , 0) ;
cntP = cntD = -1 ;
if(te <= 1)
{
bfs(c.x , c.y , 1) ;
}
else
{
bfs(c.x , c.y , 2) ;
mem(vis , 0) ;
bfs2(e.x , e.y) ;
}
int i , j ;
MIN = inf ;
if(te > 1) // 注意此处,想一想
{
for(i = 0 ; i < m ; i ++)
{
for(j = 0 ; j < n ; j ++)
{
if(ci[i][j] > 1)
{
if(MIN > dP[i][j] + dD[i][j] + 2)
MIN = dP[i][j] + dD[i][j] + 2 ;
}
}
}
}
if(flag)
{
if(te <= 1)
{
if(MIN > dP[e.x][e.y])
MIN = dP[e.x][e.y] ;
printf("%d\n" , MIN) ;
}
else
{
MIN = min(MIN , dP[e.x][e.y]) ;
if(cntP >= 0 && cntD >= 0)
{
if(kkD[0].x == kkP[0].x && kkD[0].y == kkP[0].y)
{
if(cntP > 0)
{
MIN = min(MIN , kkP[1].d + kkD[0].d + 1) ;
}
if(cntD > 0)
{
MIN = min(MIN , kkP[0].d + kkD[1].d + 1) ;
}
}
else
{
MIN = min(MIN , kkD[0].d + kkP[0].d + 1) ;
}
}
printf("%d\n" , MIN) ;
}
}
else
{
if(te <= 1)
{
puts("impossible") ;
return ;
}
else
{
if(cntP < 0 || cntD < 0)
{
puts("impossible") ;
return ;
}
if(kkD[0].x == kkP[0].x && kkD[0].y == kkP[0].y)
{
if(cntP > 0)
{
MIN = min(MIN , kkP[1].d + kkD[0].d + 1) ;
}
if(cntD > 0)
{
MIN = min(MIN , kkP[0].d + kkD[1].d + 1) ;
}
}
else
{
MIN = min(MIN , kkD[0].d + kkP[0].d + 1) ;
}
printf("%d\n" , MIN) ;
return ;
}
}
} int main()
{
int T ;
scanf("%d" , &T) ;
while (T --)
{
init() ;
solve() ;
}
return 0 ;
} /*
9
4 10
##########
#.P..#*..#
#*......D#
##########
3 9
#########
#P.#..D.#
#########
3 7
#######
#P*D#*#
#######
3 8
########
P*.#..D#
####*###
3 5
#####
#P.D#
#####
3 5
#####
#P*D#
#####
3 5
#####
#P..#
#####
5 10
##########
#.P..#*..#
#.....####
#*......D#
##########
3 9
#########
#P*D...*#
######### */

LA 5966 Blade and Sword (双向bfs + 想法) - from lanshui_Yang的更多相关文章

  1. UVALive 5966 Blade and Sword -- 搜索(中等题)

    题意:给一幅地图,P为起点,D为终点,'*'为传送阵,到达传送阵可以传到任意一个其他的传送阵,传到以后可以正常走或者再传回来,问P->D最短步数. 分析:这题一定要细心,分析要到位才能搞定,错一 ...

  2. POJ1915Knight Moves(单向BFS + 双向BFS)

    题目链接 单向bfs就是水题 #include <iostream> #include <cstring> #include <cstdio> #include & ...

  3. HDU 3085 Nightmare II 双向bfs 难度:2

    http://acm.hdu.edu.cn/showproblem.php?pid=3085 出的很好的双向bfs,卡时间,普通的bfs会超时 题意方面: 1. 可停留 2. ghost无视墙壁 3. ...

  4. POJ 3170 Knights of Ni (暴力,双向BFS)

    题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...

  5. [转] 搜索之双向BFS

    转自:http://www.cppblog.com/Yuan/archive/2011/02/23/140553.aspx 如果目标也已知的话,用双向BFS能很大程度上提高速度. 单向时,是 b^le ...

  6. 双向BFS

    转自“Yuan” 如果目标也已知的话,用双向BFS能很大提高速度 单向时,是 b^len的扩展. 双向的话,2*b^(len/2)  快了很多,特别是分支因子b较大时 至于实现上,网上有些做法是用两个 ...

  7. HDU 3085 Nightmare Ⅱ (双向BFS)

    Nightmare Ⅱ Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  8. HDU 3085 Nightmare Ⅱ 双向BFS

    题意:很好理解,然后注意几点,男的可以一秒走三步,也就是三步以内的都可以,鬼可以穿墙,但是人不可以,鬼是一次走两步 分析:我刚开始男女,鬼BFS三遍,然后最后处理答案,严重超时,然后上网看题解,发现是 ...

  9. POJ 3126 Prime Path 解题报告(BFS & 双向BFS)

    题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...

随机推荐

  1. DNS域欺骗攻击详细教程之Linux篇

    .DNS域欺骗攻击原理 DNS欺骗即域名信息欺骗是最常见的DNS安全问题.当一 个DNS服务器掉入陷阱,使用了来自一个恶意DNS服务器的错误信息,那么该DNS服务器就被欺骗了.DNS欺骗会使那些易受攻 ...

  2. Unix/Linux环境C编程入门教程(18) kali-linuxCCPP开发环境搭建

    1. Kali linux是BT5的晋级版本,用于信息安全.基于Debian7内核.新建虚拟机. 2. 选择默认虚拟机 3. 选择稍后安装操作系统 4.选择Linux Debian7 64位,因为Ka ...

  3. uva 10453 - Make Palindrome(dp)

    题目链接:10453 - Make Palindrome 题目大意:给出一个字符串,通过插入字符使得原字符串变成一个回文串,要求插入的字符个数最小,并且输出最后生成的回文串. 解题思路:和uva 10 ...

  4. 关于iOS中用AudioFile相关API解码或播放AAC_HE_V2时仅仅能识别单声首22.05k採样率的问题

    关于iOS中用AudioFile相关API解码或播放AAC_HE_V2时仅仅能识别单声首22.05k採样率的问题 在官方AQPlayer Demo 和 aqofflinerender中.都用了Audi ...

  5. C#复制数据库,将数据库数据转到还有一个数据库

    本文章以一个表为例,要转多个表则可将DataSet关联多个表.以下给出完整代码.包含引用以及main函数与复制函数. 要说明的是,必须先用Sql语句复制表结构,才干顺利的使用下面代码复制数据. usi ...

  6. UVA 103 Stacking Boxes 套箱子 DAG最长路 dp记忆化搜索

    题意:给出几个多维的箱子,如果箱子的每一边都小于另一个箱子的对应边,那就称这个箱子小于另一个箱子,然后要求能够套出的最多的箱子. 要注意的是关系图的构建,对箱子的边排序,如果分别都小于另一个箱子就说明 ...

  7. Apache经常使用配置

      Apache採用IBM HTTPServer,内核为Apache/2.0.47 Server version: IBM_HTTP_Server/6.1.0.13 Apache/2.0.47   查 ...

  8. 学习DTD和Schema的几个例子

    可以使用DTD(文档类型定义)来规定xml文档构建模块,可用起对xml文件进行验证.具体用法转:http://www.w3school.com.cn/dtd/dtd_intro.asp.同样也可以用S ...

  9. SQL Server数据库---》增删查改

    ***数据的插入:(增) insert into 表名(字段列表) values(值列表) 如果不写字段列表就要为表添加全部的列数据 其实into也可以省略 每次只能插入一条数据 1.如果字段可以为n ...

  10. Python核心编程读笔 10:函数和函数式编程

    第11章 函数和函数式编程 一 调用函数  1 关键字参数 def foo(x): foo_suite # presumably does some processing with 'x' 标准调用 ...