[solution] JZOJ-5781 秘密通道
JZOJ-5781【秘密通道 】solution
题面
Description
有一副$nm$的地图,有$nm$块地,每块是下列四种中的一种:
墙:用#表示,墙有4个面,分别是前面,后面,左面,右面。
起点:用C表示,为主角的起点,是一片空地。
终点:用F表示,为主角的目的地,是一片空地。
空地:用 . 表示。
其中除了墙不能穿过,其他地方都能走。
主角有以下3种操作:
1.移动到相邻的前后左右的地方,花费一个单位时间。
2.向前后左右其中一个方向发射子弹,子弹沿直线穿过,打在最近的一堵墙的一面,然后墙的这面就会形成一个开口通往秘密通道。同一时间最多只能有两个开口,若出现有3个开口,出现时间最早的开口会立即消失。该操作不用时间。
3.可以从一个与开口相邻的空地跳进去,进入秘密通道,从另外一个开口正对的空地跳出来。这个过程花费一个单位时间。
地图四周都是墙,问主角最少用多少时间从C走到F。C和F只会出现一次。
Input
第一行输入两个正整数$n$,$m$。
接下来$n$行,每行$m$个字符描述地图。
Output
输出1个整数,表示最短时间完成路途。如果无解输出nemoguce
Sample Input
Input 1
4 4
####
#.F#
#C.#
####
Input 2
6 8
########
#.##..F#
#C.##..#
#..#...#
#.....##
########
Input 3
4 5
#####
#C#.#
###F#
#####
Sample Output
Output 1
2
Output 2
4
Output 3
nemoguce
Data Constraint
对于50%的数据,$4≤ n,m≤ 15$。
对于100%的数据,$4≤ n,m≤ 500$。
Hint
总共用到8次操作,时间之和为4。如下图所示(图被吃掉了)
1.向左射一枪,在(3,1)的右面出现开口。
2.向下射一枪,在(6,2)的上面出现开口。
3.向左从(3,1)进入秘密通道,从(6,2)中出来,到达(5,2)。用1单位时间。
4.向右射一枪,在(5,7)的左面出现开口,(3,1)右面的开口消失。
5.走进(6,2)的开口,出来到(5,6)。用1单位时间。
6.向上射一枪,在(1,6)的下面出现开口。
7.经过秘密通道,走到(2,6)。用1单位时间。
8.走到终点。用1单位时间。
分割线
思路
这个题乍一眼看上去就像是一个BFS有没有,但是BFS是错误的(虽然数据水到BFS都可以那70分)
至于为什么BFS是错误的,用一个很形象的样例来解释(本人说不清)
#########
#......##
#......##
#......##
#.......#
#.....S.#
#.......#
#.......#
#.......#
#########
这里小X可以先向上和向右打一个子弹,再向右跑到边框,瞬移到上面
手动模拟小X在迷宫中的移动过程,可以发现以下结论
1.这里发射子弹并不能穿墙,所以如果小X在图中与终点不连通的话,那么永远无法到达终点,输出那串字符
2.小X可以在某一个结点$(x_i,y_i)$向周围的某两堵墙分别打一个子弹,再移动到某一个开口处,花1份时间移动到另一个开口,因此小X可以在移动到最近的墙之后花一份时间瞬移到另一个很远的墙边上。
想到这里有没有一点思路了呢?
正解做法
在某一个不是墙的结点$(x_i,y_i)$,向它周围的4个(不是墙的)上下左右结点连一条权值为1的边,向它上下左右4个方向向墙旁边的那个点连一条权值为结点$(x_i,y_i)$与四周墙的最近距离(注意是墙的!!!)的边,模型瞬间转化为了最短路,很神奇有没有!!!
这里最短路可以有很多种实现方式,据说SPFA,Dij+Heap等,不建议使用SPFA因为可能会被卡掉(虽然这里不会)
下面贴上本人巨丑的玄学Dij+Heap代码
Code
294ms,49.33MB
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
char map[503][503];
int n,m;
struct Edge{
int si,sj,ti,tj,nxt,w;
}edge[2000005];
int si,ti,sj,tj;
int head[503][503],book[503][503],dis[503][503],tot=0;
const int di[4]={0,0,1,-1},dj[4]={1,-1,0,0};
priority_queue<pair<int,pair<int,int> > > hep;
//queue< pair<int,int> > q;
int gmin(int a,int b){return a<b?a:b;}
void add(int sti,int stj,int toi,int toj,int we){
edge[tot].si=sti;
edge[tot].sj=stj;
edge[tot].ti=toi;
edge[tot].tj=toj;
edge[tot].w=we;
edge[tot].nxt=head[sti][stj];
head[sti][stj]=tot;
tot++;
}
int main(){
freopen("portal.in","r",stdin);
freopen("portal.out","w",stdout);
memset(head,-1,sizeof(head));
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++)
scanf("%s",map[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(map[i][j]=='C'){
si=i;sj=j;
}
if(map[i][j]=='F'){
ti=i;tj=j;
}
}
for(int i=1;i<n-1;i++)
for(int j=1;j<m-1;j++)
if(map[i][j]!='#'){
int ni,nj,minn=inf;
for(int k=0;k<4;k++){
ni=i+di[k];
nj=j+dj[k];//cout<<i<<' '<<j<<' '<<k<<endl;
if(map[ni][nj]!='#')
add(i,j,ni,nj,1);
}
int nti[4],ntj[4];
for(int k=0;k<4;k++){//cout<<1<<endl;
ni=i;nj=j;int cnt=0;
while(map[ni][nj]!='#'){
ni+=di[k];nj+=dj[k];cnt++;
}
ni-=di[k];nj-=dj[k];
nti[k]=ni;ntj[k]=nj;
minn=gmin(minn,cnt);
}
for(int k=0;k<4;k++)
add(i,j,nti[k],ntj[k],minn);
}
memset(dis,0x3f,sizeof(dis));
memset(book,0,sizeof(book));
hep.push(make_pair(0,make_pair(si,sj)));
dis[si][sj]=0;
/*q.push(make_pair(si,sj));
while(!q.empty()){
int ni=q.front().first,nj=q.front().second;
book[ni][nj]=0;
q.pop();
for(int i=head[ni][nj];i!=-1;i=edge[i].nxt){
int nti=edge[i].ti,ntj=edge[i].tj,w=edge[i].w;
if(dis[nti][ntj]>dis[ni][nj]+w){
dis[nti][ntj]=dis[ni][nj]+w;
if(!book[nti][ntj]){
q.push(make_pair(nti,ntj));
book[nti][ntj]=1;
}
}
}
}*/
while(!hep.empty()){
int ni=hep.top().second.first,nj=hep.top().second.second;//cout<<"pp"<<endl;
hep.pop();
if(book[ni][nj]==0){
book[ni][nj]=1;
for(int i=head[ni][nj];i!=-1;i=edge[i].nxt){
int nti=edge[i].ti,ntj=edge[i].tj,w=edge[i].w;
if(dis[nti][ntj]>dis[ni][nj]+w){
dis[nti][ntj]=dis[ni][nj]+w;
hep.push(make_pair(0-dis[nti][ntj],make_pair(nti,ntj)));
}
}
}
}
if(dis[ti][tj]==inf)
printf("nemoguce\n");
else
printf("%d\n",dis[ti][tj]);
//for(int i=0;i<tot;i++){
// cout<<i<<' '<<edge[i].si<<' '<<edge[i].sj<<' '<<edge[i].ti<<' '<<edge[i].tj<<' '<<edge[i].w<<endl;
//}
//for(int i=0;i<n;i++){
// for(int j=0;j<m;j++){
// cout<<map[i][j]<<' ';
// }cout<<endl;
//}
return 0;
}
[solution] JZOJ-5781 秘密通道的更多相关文章
- [jzoj 5781]【NOIP提高A组模拟2018.8.8】秘密通道 (最短路)
传送门 Description 有一副nm的地图,有nm块地,每块是下列四种中的一种: 墙:用#表示,墙有4个面,分别是前面,后面,左面,右面. 起点:用C表示,为主角的起点,是一片空地. 终点:用F ...
- [solution] JZOJ 5459. 密室
[solution] JZOJ 5459. 密室 Description 小X 正困在一个密室里,他希望尽快逃出密室. 密室中有$N$ 个房间,初始时,小X 在1 号房间,而出口在N 号房间. 密室的 ...
- [JZOJ5781]【NOIP提高A组模拟2018.8.8】秘密通道
Description 有一副n*m的地图,有n*m块地,每块是下列四种中的一种:墙:用#表示,墙有4个面,分别是前面,后面,左面,右面.起点:用C表示,为主角的起点,是一片空地.终点:用F表示,为主 ...
- IO流与IO缓冲
1.字节与字符的演变 public class inputStream { public static void test1() throws Exception{ File file= new Fi ...
- 纪中2018暑假培训day3提高a组改题记录(混有部分b组)
day3 模拟赛,看了看a组题,发现是博弈论,非常开心(因为好玩),于是做的a组.结果差点爆零,死命纠结t1的sg函数,但其实只是一个dp,不用扯到sg函数的那种. t1: Description 被 ...
- SteveY对Amazon和Google平台的吐槽
Steve Yegge, Amazon的前员工,现任Google员工,其本来想在Google+上和Google的员工讨论一些关于平台的东西,结果不小心把圈子设成了Public,结果这篇文章就公开给了全 ...
- 审计系统---初识堡垒机180501【all】
堡垒机背景[审计系统] SRE是指Site Reliability Engineer (/运维工程师=运行维护 业务系统) 运维: 维护系统,维护业务,跟业务去走 防火墙: 禁止不必要的访问[直接访问 ...
- POJ2251-Dungeon Master(3维BFS)
You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of un ...
- final文案+美工展示
作业要求:https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/1438 团队介绍:thunder 组成员及各位博客地址: 1.王航:htt ...
随机推荐
- ARM920T的Cache
转载自:http://www.eefocus.com/mcu-dsp/242034 ARM920T有16K的数据Cache和16K的指令Cache,这两个Cache是基本相同的,数据Cache多了一些 ...
- laravel中消息通知功能
以laravel5.5为例子,这个功能laravel自带的有: 1.生成表文件的migration文件,再migrate一下在数据库里生成表.命令为:php artisan notifications ...
- openStack instance error 恢复
cli command下加载openstack超级管理员权限 重设openStack 虚拟机error实例状态即可 nova reset-state instance-id --active
- PHP实现JS点击点击定位
点击class='women' 定位到 class='m=foot'$(".women").on('click',function(){ $("html, body&qu ...
- Linux命令:pwd
打印当前目录的完全路径. -L 打印路径包含符合路径 -P 打印路径不含符合路径. -LP,可能打印的不同,取决于你对进入当前目录的方式是通过符号链接进入,还是物理目录进入.如果是符号链接进入,则-L ...
- Unity for VsCode
安装以下两个插件 以下设置VsCode在换行保存时不删除tab空格
- test case VS test scenario
---恢复内容开始--- 1. test case: how to test --如何测试 test scenario: what to be tested --测试什么 2. test scen ...
- VMware虚拟机配置嵌套虚拟化
VMware虚拟机下创建kvm-sever,server下继续创建kvm虚拟机(嵌套虚拟化),返回libvirt错误解决办法:SSH连接VMwarevi /etc/vmware/config增加一行设 ...
- 了解各种不同意义上的new
问题1:请说明new operator 和 operator new的差异? 1.new operator : 一般我们写代码的时候,例如:String *p = new String(&quo ...
- as3中的embed
actionscript3允许把外部swf直接用Embed标记嵌入到主类中(当然用UrlLoader动态加载也行) 原 作者:菩提树下的杨过出处:http://yjmyzz.cnblogs.com 关 ...