题意:给一幅地图,P为起点,D为终点,'*'为传送阵,到达传送阵可以传到任意一个其他的传送阵,传到以后可以正常走或者再传回来,问P->D最短步数。

分析:这题一定要细心,分析要到位才能搞定,错一点都WA。有两种思路:

1.走到一个传送点之后,将所有能传到的地方都加入队列,然后清除传送阵向量(vector),因为以后不用再互相传了,对于某个传送阵k,以后从别的点传到k的效果还不如从这个点传到k,所以清空传送阵,又因为其他传送阵可以传回来,此时传送阵向量要把当前传送阵push_back进去,以便其他点传过来,每个传送点设一个标记,flag=0说明这个传送点还没用过,flag=1说明这个传送点是被传过来的,还可以传一次,use[][]数组记录某个传送点被用过没有(即通过它传出去过没有),然后搞即可。

代码:(63ms, 0KB)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#define Mod 1000000007
using namespace std;
#define N 1000017 char ss[][];
bool vis[][],use[][];
int n,m,step;
int dx[] = {,,,-};
int dy[] = {,-,,};
struct node
{
int x,y,tag;
node(int _x,int _y,int _tag)
{
x = _x;
y = _y;
tag = _tag;
}
node(){}
}P,D;
vector<node> trans; bool OK(int nx,int ny)
{
if(nx >= && nx < n && ny >= && ny < m)
return ;
return ;
} bool bfs()
{
queue<node> que;
memset(vis,,sizeof(vis));
memset(use,,sizeof(use));
que.push(P);
int i,j,k;
vis[P.x][P.y] = ;
while(!que.empty())
{
int SIZE = que.size();
while(SIZE--)
{
node tmp = que.front();
que.pop();
int nx = tmp.x;
int ny = tmp.y;
if(nx == D.x && ny == D.y)
return ;
if(ss[nx][ny] == '*') //tag = 1 : 被传过来的,tag = 0 : 传出去
{
if(tmp.tag == || (tmp.tag== && !use[nx][ny]))
{
for(i=;i<trans.size();i++)
{
int x = trans[i].x;
int y = trans[i].y;
if(vis[x][y] || (nx == x && ny == y))
continue;
trans[i].tag = ;
que.push(trans[i]);
}
trans.clear();
trans.push_back(tmp); //这个点还可以被传回来
if(tmp.tag == ) //被传过来并且没用过的,现在用过了
vis[nx][ny] = ;
use[nx][ny] = ;
}
if(tmp.tag == ) //被传,用过了,就当做普通点好了 别用else if
{
for(k=;k<;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(!OK(kx,ky) || ss[kx][ky] == '#' || ss[kx][ky] == '*' || vis[kx][ky])
continue;
vis[kx][ky] = ;
que.push(node(kx,ky,));
}
vis[nx][ny] = ;
}
}
else //普通点,普通走法
{
for(k=;k<;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(!OK(kx,ky) || ss[kx][ky] == '#' || vis[kx][ky])
continue;
if(ss[kx][ky] != '*' ) //如果是'*',则不能确定
vis[kx][ky] = ;
que.push(node(kx,ky,));
}
}
}
step++;
}
return ;
} int main()
{
int t,cs = ,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
trans.clear();
for(i=;i<n;i++)
{
scanf("%s",ss[i]);
for(j=;j<m;j++)
{
if(ss[i][j] == '*')
trans.push_back(node(i,j,));
else if(ss[i][j] == 'P')
P = node(i,j,);
else if(ss[i][j] == 'D')
D = node(i,j,);
}
}
step = ;
if(bfs())
printf("Case %d: %d\n",cs++,step);
else
printf("Case %d: impossible\n",cs++);
}
return ;
}

2.统计传送点的数量,如果只有一个传送点,那么不能经过传送点到达,只能走普通路到终点。否则,先走一遍普通路ans = bfs(),再从P搜一个与他最近的传送点,从D搜一个与它最近的传送点,判断这两个传送点是不是同一个,如果是只能再通过图中另一个传送点作为终中继,此时ans = bfsP()+bfsD()+2,不是同一个那就更好处理了,ans = bfsP+bfsD+1。细节问题看代码吧。

代码:(22ms, 0KB)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define Mod 1000000007
using namespace std;
#define N 1000017 struct node
{
int x,y,step;
}P,D; int n,m;
int cnt1,cnt2;
char ss[][];
int vis[][];
queue<node> que;
int dx[] = {,,,-};
int dy[] = {,-,,};
int X1,X2,Y1,Y2; int OK(int nx,int ny)
{
if(nx >= && nx < n && ny >= && ny < m && ss[nx][ny] == '.')
return ;
return ;
} int bfsPD()
{
while(!que.empty())
que.pop();
P.step = ;
memset(vis,,sizeof(vis));
que.push(P);
vis[P.x][P.y] = ;
while(!que.empty())
{
node now = que.front();
que.pop();
int nx = now.x;
int ny = now.y;
int step = now.step;
for(int k=;k<;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(ss[kx][ky] == 'D')
return step+;
if(!OK(kx,ky) || vis[kx][ky]) //不考虑'*'
continue;
node tmp;
tmp.x = kx;
tmp.y = ky;
tmp.step = step + ;
vis[kx][ky] = ;
que.push(tmp);
}
}
return Mod;
} int bfsP() //从P找'*'
{
int dis = Mod;
while(!que.empty())
que.pop();
memset(vis,,sizeof(vis));
P.step = ;
que.push(P);
vis[P.x][P.y] = ;
while(!que.empty())
{
node now = que.front();
que.pop();
int nx = now.x;
int ny = now.y;
int step = now.step;
if(step >= dis)
return dis;
for(int k=;k<;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(ss[kx][ky] == '*')
{
X1 = kx;
Y1 = ky;
cnt1++;
dis = step + ;
}
else if(OK(kx,ky))
{
if(!vis[kx][ky])
{
node tmp;
tmp.x = kx;
tmp.y = ky;
tmp.step = step+;
vis[kx][ky] = ;
que.push(tmp);
}
}
}
}
return dis;
} int bfsD() //从D找'*'
{
int dis = Mod;
while(!que.empty())
que.pop();
memset(vis,,sizeof(vis));
D.step = ;
que.push(D);
vis[D.x][D.y] = ;
while(!que.empty())
{
node now = que.front();
que.pop();
int nx = now.x;
int ny = now.y;
int step = now.step;
if(step >= dis)
return dis;
for(int k=;k<;k++)
{
int kx = nx + dx[k];
int ky = ny + dy[k];
if(ss[kx][ky] == '*')
{
X2 = kx;
Y2 = ky;
cnt2++;
dis = step + ;
}
else if(OK(kx,ky))
{
if(!vis[kx][ky])
{
node tmp;
tmp.x = kx;
tmp.y = ky;
tmp.step = step+;
vis[kx][ky] = ;
que.push(tmp);
}
}
}
}
return dis;
} int main()
{
int t,cs = ,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int cnt = ;
for(i=;i<n;i++)
{
scanf("%s",ss[i]);
for(j=;j<m;j++)
{
if(ss[i][j] == 'P')
P.x = i,P.y = j;
else if(ss[i][j] == 'D')
D.x = i,D.y = j;
else if(ss[i][j] == '*')
cnt++;
}
}
int ans = ;
cnt1 = cnt2 = ;
if(cnt <= ) //少于等于1个传送点,就只能按普通路走过去
ans = bfsPD();
else
{
int d1,d2;
ans = bfsPD();
d1 = bfsP();
d2 = bfsD();
if(cnt1 == cnt2 && cnt1 == ) //周围都只有一个点,通过这两个点中介
{
if(X1 == X2 && Y1 == Y2) //是同一个点,因为至少还有一个点,所以可以传回来
ans = min(ans,d1+d2+);
else
ans = min(ans,d1+d2+);
}
else //有不止一个点,可以用不同点传
ans = min(ans,d1+d2+);
}
if(ans >= Mod)
printf("Case %d: impossible\n",cs++);
else
printf("Case %d: %d\n",cs++,ans);
}
return ;
}

Written by Whatbeg

UVALive 5966 Blade and Sword -- 搜索(中等题)的更多相关文章

  1. LA 5966 Blade and Sword (双向bfs + 想法) - from lanshui_Yang

    题目大意:给你一张有n * m个网格的图,每个网格可能是如下符号: “#”:墙 “P”:出发点 “D”:终点 “.”:空地 “*”:传送机 有一个旅行家(假设名叫Mike),他要从点P到达点D,途中必 ...

  2. 搜索 水题&&错误集锦

    引子: 本以为搜索的题目老师也不会检查,结果今天早上loli慢悠悠的说:“请同学们提交一下搜索的题目~”,顿时心旌摇曳,却也只能装作镇定自若的样子,点了点头.. 然后就开始了今天的疯狂做题,虽说题目都 ...

  3. lintcode 中等题:搜索旋转排序数组II

    题目 搜索旋转排序数组 II 跟进“搜索旋转排序数组”,假如有重复元素又将如何? 是否会影响运行时间复杂度? 如何影响? 为何会影响? 写出一个函数判断给定的目标值是否出现在数组中. 样例 给出[3, ...

  4. poj1088(记忆化搜索入门题)

    题目链接:http://poj.org/problem?id=1088 思路: 明显的记忆化搜索题,用dp[i][j]表示从(i,j)出发能滑的最远距离,用dfs搜索,若dp[x][y]>0即已 ...

  5. 【搜索好题】bzoj1501 [NOI2005]智慧珠游戏

    bzoj1501 [NOI2005]智慧珠游戏 搜索苟逼题系列. 暴力枚举每一种情况(包括旋转翻转全都考虑在内)然后码出代码. (正解似乎不是这样子的) 那年好像还有平衡树苟逼题维护数列233333心 ...

  6. hdu 1181:变形课(搜索水题)

    变形课 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submis ...

  7. 【LOJ6043】「雅礼集训 2017 Day7」蛐蛐国的修墙方案(搜索技巧题)

    点此看题面 大致题意: 给你一个长度为\(n\)的排列\(p\),要求构造一个合法的括号序列,使得如果第\(i\)个位置是左括号,则第\(p_i\)个位置一定是右括号. 暴搜 很容易想出一个暴搜. 即 ...

  8. 搜索水题四连发_C++

    特别声明:以下题目有部分为原创题,涉及版权问题,不得转载,违者追究 法律责任! 话说这是一套神题,只有你想不到,没有你做不到 题目更正后比 Pascal 跑得还快哈~ 一道特别裸,但是特别坑的搜索题 ...

  9. 搜索刷题记录by cellur925

    我好菜啊!连暴搜都不会! 注意边界退出! 特开此帖,记录搜索学习之路!(逃) 1.全排列 2.八皇后 3.数的划分 由于此题有同一划分方法算一个的限制,我们为了避免搜多,可以使搜出的结果满足单调不降性 ...

随机推荐

  1. 数据库==>>数据查询基础

    数据查询基础 还好吗?几天不见,甚是思念呀!笑对人生,好好生活,快快乐乐的迎接我们的美好未来吧! 好吧!抒情结束,我们一起来学习一下我们今天的主题:数据查询基础,很有意思哟.让我们来感受它的魅力吧! ...

  2. 打印机问题win7 和xp

    服务器端问题,重启如下服务 net stop "print spooler" net start "print spooler" gpedit.msc 本地计算 ...

  3. SQL SERVER获取数据库文件信息

        MS SQL SERVER 获取当前数据库文件等信息,适用于多个版本: SELECT dbf.file_id AS FileID , dbf.name AS [FileName] , s.fi ...

  4. 关于SQL Server的WITH(NOLOCK)和(NOLOCK)

    The difference is that you should be using the syntax WITH (NOLOCK) (or WITH (<any table hint> ...

  5. python基础(2)

    1.lambda函数 学习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,函数同样有简单的表示方法 # ###################### 普通函数 ######### ...

  6. 第一个WCF的程序

    第一个WCF的程序,按照书上的基本已经完成,就是创建配置文件那里卡住了,因为书上写的不太全,明天再进行深入调试,输入http://127.0.0.1:3721/calculatorservice/me ...

  7. Android项目结构分析

    andriod项目目录结构如下图: 1. src目录 该目录一个普通的保存java源文件的目录,其和普通java工程中的src目录是一样的. 2. gen目录 此目录用于存放所有由ADT插件自动生成的 ...

  8. MacOs终端忽略大小写

    使用MacOs的终端时,唯一让人感觉不爽的就是Tab补全是区分大小的,所以查了资料就把这个问题搞定了.在用户目录下创建 .inputrc 文件,内容为以下三行代码,保存后重启终端再次输入文件名Tab补 ...

  9. iOS8以后 UISearchController的用法

    查了不少资料,都不太全,自己查看了apple文档,写了一份代码: 如下(只是界面): 1. 声明属性 @property (nonatomic, strong) UISearchController ...

  10. 最近开始研究PMD(一款采用BSD协议发布的Java程序代码检查工具)

    PMD是一款采用BSD协议发布的Java程序代码检查工具.该工具可以做到检查Java代码中是否含有未使用的变量.是否含有空的抓取块.是否含有不必要的对象等.该软件功能强大,扫描效率高,是Java程序员 ...