穿梭时间的画面的钟 从反方向 开始移动|

tmjyh09

园龄:3年2个月粉丝:1关注:3

P3831 [SHOI2012]回家的路 题解

题目传送门

分析

解法 1:

每两个点都连边,跑裸的最短路。

显然,nm 非常大,暴力连边会 TLE 和 MLE。

解法 2(正解):

首先,对答案产生贡献的只有换乘站,所以我们只用连两种边:

  1. 一个换乘站看作 2 个节点,连边,边权为 1(站内换乘)。
  2. x 相等的换乘站相连,y 相等的换乘站相连。

其中,起点和终点也要加入图中。

建完图后,因为起点有两个,一个是 0,一个是 m+1,以这两个为源点跑最短路,再取个最小值即可。

代码

#include <bits/stdc++.h>
using namespace std;
inline int read();
inline void write(int);
int n,m;
struct poi{
int id;
int x,y;
}a[200005];
struct edge{
int to,nxt,w;
}e[1000005<<1];
int head[200005],idx;
void link(int x,int y,int w){
e[++idx]=edge{y,head[x],w};
head[x]=idx;
}
bool cmp1(poi a,poi b){
if(a.x!=b.x)return a.x<b.x;
return a.y<b.y;
}
bool cmp2(poi a,poi b){
if(a.y!=b.y)return a.y<b.y;
return a.x<b.x;
}
int ans=INT_MAX;
int dis[200005];
bool vis[200005];
void dijkstra(int s){
memset(dis,0x3f3f3f3f,sizeof dis);
memset(vis,0,sizeof vis);
priority_queue< pair<int,int>, vector<pair<int,int> >,greater<pair<int,int> > >q;
dis[s]=0;q.push(make_pair(0,s));
while (!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;
vis[u]=true;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
q.push(make_pair(dis[v],v));
}
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
a[i].x=read();a[i].y=read();a[i].id=i;
link(i,i+m+2,1);
link(i+m+2,i,1);
}
int x1=read(),y1=read(),x2=read(),y2=read();
a[0]=poi{0,x1,y1};a[m+1]=poi{m+1,x2,y2};
sort(a,a+m+2,cmp1);
for(int i=1;i<=m+1;i++){
if(a[i-1].x==a[i].x){
link(a[i-1].id,a[i].id,abs(a[i].y-a[i-1].y)*2);
link(a[i].id,a[i-1].id,abs(a[i].y-a[i-1].y)*2);
}
}
sort(a,a+m+2,cmp2);
for(int i=1;i<=m+1;i++){
if(a[i-1].y==a[i].y){
link(a[i-1].id+m+2,a[i].id+m+2,abs(a[i].x-a[i-1].x)*2);
link(a[i].id+m+2,a[i-1].id+m+2,abs(a[i-1].x-a[i].x)*2);
}
}
dijkstra(0);
ans=min(dis[m+1],dis[2*m+3]);
dijkstra(m+2);
ans=min(ans,min(dis[m+1],dis[2*m+3]));
write(ans!=0x3f3f3f3f?ans:-1);
return 0;
}
inline int read(){
register int x=0,f=0;
register char ch=getchar();
while(!isdigit(ch))f^=!(ch^45),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
inline void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>=10)write(x/10);
putchar(x%10+'0');
}

本文作者:tmjyh09

本文链接:https://www.cnblogs.com/tmjyh09/p/15845148.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   tmjyh09  阅读(62)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起