UVALive 5966 Blade and Sword -- 搜索(中等题)
题意:给一幅地图,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 -- 搜索(中等题)的更多相关文章
- LA 5966 Blade and Sword (双向bfs + 想法) - from lanshui_Yang
题目大意:给你一张有n * m个网格的图,每个网格可能是如下符号: “#”:墙 “P”:出发点 “D”:终点 “.”:空地 “*”:传送机 有一个旅行家(假设名叫Mike),他要从点P到达点D,途中必 ...
- 搜索 水题&&错误集锦
引子: 本以为搜索的题目老师也不会检查,结果今天早上loli慢悠悠的说:“请同学们提交一下搜索的题目~”,顿时心旌摇曳,却也只能装作镇定自若的样子,点了点头.. 然后就开始了今天的疯狂做题,虽说题目都 ...
- lintcode 中等题:搜索旋转排序数组II
题目 搜索旋转排序数组 II 跟进“搜索旋转排序数组”,假如有重复元素又将如何? 是否会影响运行时间复杂度? 如何影响? 为何会影响? 写出一个函数判断给定的目标值是否出现在数组中. 样例 给出[3, ...
- poj1088(记忆化搜索入门题)
题目链接:http://poj.org/problem?id=1088 思路: 明显的记忆化搜索题,用dp[i][j]表示从(i,j)出发能滑的最远距离,用dfs搜索,若dp[x][y]>0即已 ...
- 【搜索好题】bzoj1501 [NOI2005]智慧珠游戏
bzoj1501 [NOI2005]智慧珠游戏 搜索苟逼题系列. 暴力枚举每一种情况(包括旋转翻转全都考虑在内)然后码出代码. (正解似乎不是这样子的) 那年好像还有平衡树苟逼题维护数列233333心 ...
- hdu 1181:变形课(搜索水题)
变形课 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submis ...
- 【LOJ6043】「雅礼集训 2017 Day7」蛐蛐国的修墙方案(搜索技巧题)
点此看题面 大致题意: 给你一个长度为\(n\)的排列\(p\),要求构造一个合法的括号序列,使得如果第\(i\)个位置是左括号,则第\(p_i\)个位置一定是右括号. 暴搜 很容易想出一个暴搜. 即 ...
- 搜索水题四连发_C++
特别声明:以下题目有部分为原创题,涉及版权问题,不得转载,违者追究 法律责任! 话说这是一套神题,只有你想不到,没有你做不到 题目更正后比 Pascal 跑得还快哈~ 一道特别裸,但是特别坑的搜索题 ...
- 搜索刷题记录by cellur925
我好菜啊!连暴搜都不会! 注意边界退出! 特开此帖,记录搜索学习之路!(逃) 1.全排列 2.八皇后 3.数的划分 由于此题有同一划分方法算一个的限制,我们为了避免搜多,可以使搜出的结果满足单调不降性 ...
随机推荐
- http 响应码
一.HTTP码应码响应码由三位十进制数字组成,它们出现在由HTTP服务器发送的响应的第一行. 响应码分五种类型,由它们的第一位数字表示:1.1xx:信息,请求收到,继续处理2.2xx:成功,行为被成功 ...
- Represent code in math equations
Introduce The article shows a way to use math equations to represent code's logical. Key ideas logic ...
- Introduction to ASP.NET 5
ASP.NET 5 is a significant redesign of ASP.NET. This topic introduces the new concepts in ASP.NET 5 ...
- JavaScript hasOwnProperty() 函数详解
hasOwnProperty()函数用于指示一个对象自身(不包括原型链)是否具有指定名称的属性.如果有,返回true,否则返回false. 该方法属于Object对象,由于所有的对象都"继承 ...
- cl_gui_cfw=>dispatch
将已经触发的EVENT发送给他们各自的EVENT HANDLER,以便让这些事件得到响应. 根据返回值可以判断是否发送成功. CALL METHOD cl_gui_cfw=>dispatch ...
- 参加:白帽子活动-赠三星(SAMSUNG) PRO....
参加:白帽子活动-—赠三星(SAMSUNG) PRO.... Everybody~小i在这里提前祝大家国庆假期愉快,咱们期待已久的国庆活动终于开始拉,下面进入正题,恩,很正的题! 活动地址:http: ...
- 软件快速开发平台 JEPF
JEPF新一代软件快速开发平台(Java Elephant Platform)是一款优秀的平台产品,它本着灵活.快捷开发.高性能.高协作性.高稳定性.高可用性.人性化的操作体验为设计宗旨历经2年研发成 ...
- 响应式SharePoint模版页
一张好的皮肤显然的会给你的项目加分不少.特别是大部分的项目,UI甚至可以决定成败. SharePoint在这方面一直都做得不好,曾经我有好多项目都是坐在美工旁边来一起修改样式.痛苦的经历. 不久以前, ...
- CentOS6.5上编译OpenJDK7源码
本文地址:http://www.cnblogs.com/wuyudong/p/build-openjdk7.html,转载请注明源地址. 采用开源的OpenJDK版本,获取其源码的方式有两种: 通Me ...
- 【读书笔记】iOS-类别
一,类别是一种为现有的类添加新方法的方式. 二,类别的局限性. 1,无法向类中添加新的实例变量.类别没有位置容纳实例变量. 2,名称冲突,即类别中的方法与现有的方法重名.当发生名称冲突时,类别具有更高 ...