P4442 [COCI2017-2018#3] Portal

首先考虑传送门的作用,那就是使我能更快地走到终点,也就是跳过一段路经。

那么既然这样,我们就在需要传送时先打传送门,然后找到一个墙打传送门再传送即可。

很明显选择的墙即是离自己最近的墙。

但是这样明显麻烦了,实际上一定会存在自己或另一个不是墙的点能同时打到离自己最近的墙与要打传送门的墙。

考虑证明,其实很简单,如果不存在这个位置,那么离自己最近的墙一定是能同时打到他们的点,这样打到的墙就不符合要求了。

那么我们可以先预处理建图,然后跑最短路。

预处理建图时先找到每一个点四周的墙,其中离的最近的墙是自己的传送起点,而较远的其他墙是传送终点,对每个传送终点连接边权为到传送起点的时间加传送时间的边即可。

然后对于每一个点,向相邻非墙点连边,跑最短路即可。

时间复杂度:O(n×m×log(n×m))

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int N=505;
int n,m,x1,y1,x2,y2,dis[N*N];
char s[N][N];
vector<int>b[N*N];
vector<pair<int,int> >a[N*N];
inline int clac(int x,int y)
{
return (x-1)*m+y;
}
inline pair<int,int> position(int x)
{
return {(x-1)/m+1,(x-1)%m+1};
}
inline int tabs(int x)
{
return x>0?x:-x;
}
inline int distance(int x,int y)
{
int xt=position(x).first,yt=position(x).second,xp=position(y).first,yp=position(y).second;
return tabs(xt-xp)+tabs(yt-yp);
}
struct node2
{
int name,data;
};
priority_queue<node2>q;
bool operator <(node2 fi,node2 se)
{
return fi.data>se.data;
}
void dijstra()
{
memset(dis,0x3f,sizeof(dis));
dis[clac(x1,y1)]=0;
q.push({clac(x1,y1),0});
while(!q.empty())
{
int x=q.top().name;
q.pop();
int len=a[x].size();
for(int i=0;i<len;i++)
{
if(dis[x]+a[x][i].second<dis[a[x][i].first])
{
dis[a[x][i].first]=a[x][i].second+dis[x];
q.push({a[x][i].first,dis[a[x][i].first]});
}
}
}
}
int main()
{
freopen("portal.in","r",stdin);
freopen("portal.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)
{
int bef=0;
for(int j=1;j<=m;j++)
{
if(s[i][j]=='#')bef=j;
else if(bef)b[clac(i,j)].push_back(clac(i,bef+1));
}
bef=0;
for(int j=m;j>=1;j--)
{
if(s[i][j]=='#')bef=j;
else if(bef)b[clac(i,j)].push_back(clac(i,bef-1));
}
}
for(int j=1;j<=m;j++)
{
int bef=0;
for(int i=1;i<=n;i++)
{
if(s[i][j]=='#')bef=i;
else if(bef)b[clac(i,j)].push_back(clac(bef+1,j));
}
bef=0;
for(int i=n;i>=1;i--)
{
if(s[i][j]=='#')bef=i;
else if(bef)b[clac(i,j)].push_back(clac(bef-1,j));
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(s[i][j]=='#')continue;
if(s[i][j]=='C')x1=i,y1=j;
if(s[i][j]=='F')x2=i,y2=j;
int len=b[clac(i,j)].size();
int minn=1e9;
for(int k=0;k<len;k++)minn=min(minn,distance(b[clac(i,j)][k],clac(i,j)));
for(int k=0;k<len;k++)a[clac(i,j)].push_back({b[clac(i,j)][k],minn+1});
if(i>1&&s[i-1][j]!='#')a[clac(i,j)].push_back({clac(i-1,j),1});
if(i<n&&s[i+1][j]!='#')a[clac(i,j)].push_back({clac(i+1,j),1});
if(j>1&&s[i][j-1]!='#')a[clac(i,j)].push_back({clac(i,j-1),1});
if(j<m&&s[i][j+1]!='#')a[clac(i,j)].push_back({clac(i,j+1),1});
}
}
dijstra();
if(dis[clac(x2,y2)]>1e9)printf("nemoguce");
else printf("%d",dis[clac(x2,y2)]);
return 0;
}
posted @   Gmt丶Fu9ture  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示