ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

秘密通道

2020-11-30 16:58:10  阅读:26429  来源: 互联网

标签:Node sy int 秘密 传送门 MaxN 通道 dis


题目

传送门 to usOJ

题目描述
s y \tt sy sy 有个文件夹叫做 “曲径通幽处” 。今天他要用这一招来更快的移动!

具体而言,地图中有「墙」、「空地」两种地形。「墙」是不可以达到的位置,而「空地」则可以任意次数到达。 s y \tt sy sy 每 1 s 1\text{s} 1s 可以往上下左右任意一个方向走一步,到达下一个格子。

s y \tt sy sy 的特殊技能来了:他可以往东南西北任意一个方向丢出一个「铯铥」。「铯铥」沿直线飞行,直到 下一个格子 是「墙」,所以「铯铥」一定在「空地」上。

场地上只会有两个「铯铥」——出现第三个时,最早出现的那个即刻消失。

s y \tt sy sy 在「铯铥」所在的格子上时,该「铯铥」会变为「曲径」,如果场上存在另一个「铯铥」则其变为「幽处」。 s y \tt sy sy 同样可以花费 1 s 1\text{s} 1s 从「曲径」立即到达「幽处」所在的地方。注意:此时「铯铥」并不会消失。

你能告诉 s y \tt sy sy 从 C C C 到达 F F F 最少需要多少秒吗?

数据范围与提示
地图长宽均不超过 500 500 500 。

思路

结论:一旦你进入某个传送门,你就不会需要再次从这里出来

感觉是显然的。但是人的位置不是唯一要素,传送门的位置难道毫无用处?其实确实是这样。我简单说明一下:如果你进入该传送门又从这里出来,只可能改变了另一个传送门的位置。所以只有一种情况下,这是必要的操作:人站在某个传送门前面,另一个传送门的位置有用

那么另一个传送门必须要被使用。显然不是从那里进去,因为进去的传送门,也就是「曲径」,总是可以现场制造。所以要从那里出来。可是从那里出来的时候,若使用的是现在的、在身后的传送门,那就很愚蠢了,因为你刚刚从身后的传送门里出来。所以你 必须 换一个位置制造「曲径」。于是恰好又变为了 人站在传送门前,另一个传送门的位置不能乱选

这个递归的意思是,如果这一步是应该的,那么我递归下去的这一步也是应该的,我会紧接着执行它

考虑到人和传送门的位置是有限的,必定递归成环,没有出口。所以人在传送门前的时候,另一个传送门的位置并不重要。所以你进入一个传送门,就不会需要从这里出来。所以你用过一个传送门,可以直接把它删掉,而「幽处」可以自己立刻再创造一个。所以你只需要存人的位置。所以是 O ( n 2 log ⁡ n ) \mathcal O(n^2\log n) O(n2logn) 的 d i j k s t r a \tt dijkstra dijkstra 板题。

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int MaxN = 505;
const int infty = (1<<30)-1;
const int dir[][2] = {
	{0,1},{1,0},{0,-1},{-1,0}
};
char maze[MaxN][MaxN];
int endpos[MaxN][MaxN][4]; 

struct Node{
	int x, y, dis; Node(){}
	Node(int X,int Y,int D){
		x = X, y = Y, dis = D;
	}
	bool operator < (const Node &t) const {
		return dis > t.dis;
	}
};
priority_queue< Node > q;
int dis[MaxN][MaxN], n, m;
int toWall[MaxN][MaxN]; // µ½Ç½µÄ×î½ü¾àÀë 
int bfs(){
	/* set borden as wall */ ;
	for(int i=1; i<=n; ++i)
	for(int d=0; d<4; ++d)
		endpos[i][0][d] =
		endpos[i][m+1][d] = -1;
	for(int j=1; j<=m; ++j)
	for(int d=0; d<4; ++d)
		endpos[0][j][d] =
		endpos[n+1][j][d] = -1;
	/* calculate toWall */ ;
	Node t; // ÁÙʱ±äÁ¿ 
	for(int i=1; i<=n; ++i)
	for(int j=1; j<=m; ++j){
		dis[i][j] = infty;
		toWall[i][j] = infty;
		if(maze[i][j] == '#'){
			t.dis = toWall[i][j] = 0;
			t.x = i, t.y = j;
			q.push(t);
		}
	}
	while(!q.empty()){
		t = q.top(), q.pop();
		for(int d=0; d<4; ++d){
			int i = t.x+dir[d][0];
			int j = t.y+dir[d][1];
			if(0 < i && i <= n
			&& 0 < j && j <= m
			&& toWall[i][j] > t.dis+1){
				toWall[i][j] = t.dis+1;
				q.push(Node(i,j,t.dis+1));
			}
		}
	}
	/* Ô¤´¦Àí down & right */ ;
	for(int i=n; i>=1; --i)
	for(int j=m; j>=1; --j)
	for(int d=0; d<4; ++d)
		if(maze[i][j] == '#')
			endpos[i][j][d] = -1;
		else endpos[i][j][d] = // ¾àÀë 
			endpos[i+dir[d][0]][j+dir[d][1]][d]+1;
	/* Ô¤´¦Àí up & left */ ;
	for(int i=1; i<=n; ++i)
	for(int j=1; j<=m; ++j)
	for(int d=0; d<4; ++d)
		if(maze[i][j] == '#')
			endpos[i][j][d] = -1;
		else endpos[i][j][d] =
			endpos[i+dir[d][0]][j+dir[d][1]][d]+1;
	/* ½øÐÐ bfs */ ;
	for(int i=1; i<=n; ++i)
	for(int j=1; j<=m; ++j)
		if(maze[i][j] == 'C'){
			t.dis = dis[i][j] = 0;
			t.x = i, t.y = j;
			q.push(t);
		}
	while(!q.empty()){
		t = q.top(), q.pop();
		if(t.dis > dis[t.x][t.y])
			continue; // solved
		for(int d=0; d<4; ++d){
			int i = t.x+dir[d][0];
			int j = t.y+dir[d][1];
			if(0 < i && i <= n
			&& 0 < j && j <= m
			&& maze[i][j] != '#'
			&& dis[i][j] > t.dis+1){
				dis[i][j] = t.dis+1;
				q.push(Node(i,j,t.dis+1));
			}
			i = t.x+dir[d][0]*endpos[t.x][t.y][d];
			j = t.y+dir[d][1]*endpos[t.x][t.y][d];
			if(dis[i][j] > t.dis+toWall[t.x][t.y]){
				dis[i][j] = t.dis+toWall[t.x][t.y];
				q.push(Node(i,j,dis[i][j]));
			}
		}
	}
	for(int i=1; i<=n; ++i)
	for(int j=1; j<=m; ++j)
		if(maze[i][j] == 'F')
			return dis[i][j];
	return -1; // Êý¾ÝÓÐÎó 
}

int main(){
	n = readint(), m = readint();
	for(int i=1; i<=n; ++i)
		scanf("%s",maze[i]+1);
	int ans = bfs();
	if(ans == infty)
		puts("nemoguce");
	else printf("%d\n",ans);
//	for(int i=1; i<=n; ++i,puts(""))
//	for(int j=1; j<=m; ++j)
//		printf("%d ",dis[i][j]);
	return 0;
}

标签:Node,sy,int,秘密,传送门,MaxN,通道,dis
来源: https://blog.csdn.net/qq_42101694/article/details/110390998

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有