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.数的划分 由于此题有同一划分方法算一个的限制,我们为了避免搜多,可以使搜出的结果满足单调不降性 ...
随机推荐
- RCA端子颜色(红、白、黄)
RCA端子(红白黄)的作用: 黄:视频 红:左声道 白:右声道 RCA为两口插头,红色代表左声道,白色为右声道,3.5(AUX口)同样为立体声接头,虽然它只有一个端口,同样也具有左右声道分开传输的功能 ...
- iOS 七牛云上传并获取图片----【客户端】
最近做了七牛云存储的有关内容,涉及到与后台交互获取验证的token,无奈,后台自命清高,不与理会,没办法呀,于是自己搞呗.首先呢在在七牛上注册一个账号,然后呢添加一个存储空间这时候空间名 ...
- 复杂表格的树形结构的添加删除行div实现
公司倒闭,换了工作,无奈选择了做外包这个差事,大公司进不去,小公司工资太低,可能也只能如此了.但无奈之举,亦不可浪费时间,多多磨练自己吧! 众所周知,做外包项目,其实就是做一些大公司的内部系统,多以管 ...
- Angular 核心概念
module(模块) 作用 通过模块对页面进行业务上的划分,根据不同的功能划分不同的模块. 将重复使用的指令或者过滤器之类的代码做成模块,方便复用 注意必须指定第二个参数,否则变成找到已经定义的模块 ...
- andriod 读取网络图片
来自:http://blog.csdn.net/jianghuiquan/article/details/8641283 Android手机上,我们常用ImageView显示图片,我们本章获取网络图片 ...
- Android 首页图片轮播
1.网络上的的一个框架,已经在github 上开源 github : https://github.com/gcgongchao/flashview 相关博客 : http://www.eoeand ...
- 部分博文目录索引(C语言+算法)
今天将本博客的部分文章建立一个索引,方便大家进行阅读,当然每一类别中的文章都会持续的添加和更新(PS:博文主要使用C语言) 博客地址:http://www.cnblogs.com/archimedes ...
- MyBatis入门(二)---一对一,一对多
一.创建数据库表 1.1.创建数据表同时插入数据 /* SQLyog Enterprise v12.09 (64 bit) MySQL - 5.6.27-log : Database - mybati ...
- 大家一起和snailren学java-(四)初始化与清理
初始化和清理,是一个生命周期的起始.在java中,对象的初始化和对象的回收是怎样的呢? 在开发c++的时候,有构造器的概念.即对象的创建,首先默认调用构造器进行初始化.在java中也有“构造器”.ja ...
- 2.1.12 Next Permutation 下一个字典序数组
对当前排列从后向前扫描,找到一对为升序的相邻元素,记为i和j(i < j).如果不存在这样一对为升序的相邻元素,则所有排列均已找到,算法结束:否则,重新对当前排列从后向前扫描,找到第一个大于i的 ...