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.数的划分 由于此题有同一划分方法算一个的限制,我们为了避免搜多,可以使搜出的结果满足单调不降性 ...
随机推荐
- WinJs项目介绍
WinJs库是最近微软公布的一个开源项目.它与开源社区的协作共同完成.为了轻易创建HTML/JS/CSS应用程序开发的解决方案.WinJS是一个Javascripts的工具箱让开发人员使用HT ...
- 【OpenCV】OpenCV中GPU模块使用
CUDA基本使用方法 在介绍OpenCV中GPU模块使用之前,先回顾下CUDA的一般使用方法,其基本步骤如下: 1.主机代码执行:2.传输数据到GPU:3.确定grid,block大小: 4.调用内核 ...
- xscript脚本
最近看<游戏脚本高级编程>,然后顺便把里面实现的虚拟机,汇编器以及编译器手动用C++重写了一遍,原版书中提供的代码,风格不是很好,而且有几处BUG.我现在开源的代码中已经修复了BUG,而且 ...
- ASP.NET MVC自定义AuthorizeAttribute篇知识点讲解—登录限制
1.前言 a.微软对ASP.NET的开发从WebForm到MVC的转变,已经正式过去5,6个年头,现在WebForm和MVC也都越来越完善,小小算来我也已经工作了将近三年,从大学的时候学习ASP.NE ...
- pace.js和NProgress.js两个加载进度插件的一点小总结
这两个插件都是关于加载进度动画的,应该说各有特点吧,最起码对我来说是各有优势的.今天一天就捣鼓了加载进度动画,也研究了大量的(也就这两个)加载进度动画,也算对加载进度动画有了一个初步的了解了吧. NP ...
- R语言学习笔记:SQL操作
虽然R很强大,但如果对SQL非常熟悉,也不能浪费这项技能了,可以用上sqldf包,从example("sqldf")抄了几条用法放在这里,以后可能会用上. library(&quo ...
- 【转】Android 语言切换过程分析
最近在看一个bug,系统切换语言后,本来退到后台的音乐,会在通知栏上显示通知.为了解决这个bug,我学习了下android的语言切换流程,也参考了大量其他人的资料.(主要参考了http://blog. ...
- iOS开发中的一些细节BUG的解决
这篇博客里我将不定期更新自己遇到的一些细节上的BUG,并提供解决方法,遇到同样问题的童鞋们可以参考交流一下. 1.关于tableView的tableHeaderView 请注意,我这里说的是table ...
- Silverlight项目笔记4:初识Prism以及IoC
1.Prism Prism是由微软Patterns & Practices团队开发的针对WPF和Silverlight的MVVM框架. Prism的几个关键点: (1)启动器类UnityBoo ...
- 关于EntityFramework在vs2012无法引用的问题
这段时间学习MVC,发现一个问题,我公司的电脑可以直接引用EntityFrameWork这个命名空间,但我家里面的电脑就不能直接引用,刚开始以为是我电脑配置问题,后重装电脑,发现问题并没有解决. 今天 ...