题意:给一幅地图,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. Maven仓库分类

    MAVEN仓库分类 Maven仓库分为:本地仓库+远程仓库两大类 远程仓库又分为:中央仓库+私服+其它公共远程仓库 1,在Maven中,任何一个依赖.插件或者项目构建的输出,都可以称之为构件 2,Ma ...

  2. 怎样高效地去判断Array中是否包含某个值?

    问题 怎样去判断Array(无序)中是否包含某个值呢? 这是一个在Java中经常被问到的问题.它也是Stack Overflow上投票前几的一个问题.下面将展示投票前几的几个回答,这些回答使用不同的方 ...

  3. HTML JavaScript简介

    一.JavaScript简介 1.JavaScript是个什么东西? 它是个脚本语言,需要有宿主文件,它的宿主文件是HTML文件. 2.它与Java什么关系? 没有什么直接的联系,Java是Sun公司 ...

  4. C++之多态的一个例子

    [例12.1] 先建立一个Point(点)类,包含数据成员x,y(坐标点).以它为基类,派生出一个Circle(圆)类,增加数据成员r(半径),再以Circle类为直接基类,派生出一个Cylinder ...

  5. C# Sqlite 序列

    sqlite 不能直接创建自定义函数,不能像 sql server中那样方便创建并使用.不过我们照样可以创建它,创建成功后,我们照样可以随心所欲(比如批量更新等) 序列是一个数据库中很常用的操作,在其 ...

  6. ruby 操作数据库语句

    1.多对多 user role u = User.first role = Role.first 插入 u.roles << role u.save 更新 u.roles = [] u.r ...

  7. Android 五大布局

    Android 五大布局:  FrameLayout(框架布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),Table ...

  8. 【读书笔记】iOS网络-HTTP-请求内容

    一,GET方法. 从服务器获取一段内容,用HTTP术语来说就是实体.GET请求通常不包含请求体,不过也是可以包含的.有些网络缓存设施只会缓存GET响应.GET请求通常不会导致服务器端的数据变化. 二, ...

  9. 【读书笔记】iOS-自动释放池

    一,NSObject类提供了一个autorelease方法: -(id)autorelease; 该方法预先设定了一条将来在某个时间发送的release消息,其返回值是接收消息的对象.retain消息 ...

  10. iOS开发笔记11:表单键盘遮挡、浮点数价格格式化显示、省市区选择器、View Debugging

    1.表单键盘遮挡 应用场景为一个collectionView上有多个textfield.textView供用户填写信息. 之前输入项较少时,采取的方法比较粗暴,didSelectItemAtIndex ...