Description
Input
Output
Sample Input
2 1
1 2
1 1 2 2
1 2
1 1 2 2
Sample Output
5
HINT
N<=20000,M<=100000
题解:
把图拆成两层,一层横着进行,一层竖着进行,通过可以换乘的点连接两层.
然后直接跑最短路即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
#define M 400010
using namespace std;
struct use{int x,y,id;}p[N];
struct edge{int st,en;long long v;}e[M<<1];
int point[N],next[M<<1],n,m;
int f[N],q[N*20],cnt;
long long dis[N];
bool cmp1(use a,use b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
bool cmp2(use a,use b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
bool cmp3(use a,use b){return a.id<b.id;}
void add(int x,int y,long long v){
next[++cnt]=point[x];point[x]=cnt;
e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
next[++cnt]=point[y];point[y]=cnt;
e[cnt].st=y;e[cnt].en=x;e[cnt].v=v;
}
void spfa(int s){
int h(0),t(1);
memset(dis,127/3,sizeof(dis));
q[t]=s;dis[s]=0;f[s]=1;
while (h<t){
int u=q[++h];f[u]=0;
for (int i=point[u];i;i=next[i])
if (dis[e[i].en]>dis[u]+e[i].v){
dis[e[i].en]=dis[u]+e[i].v;
if (!f[e[i].en]){
f[e[i].en]=1;
q[++t]=e[i].en;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m+2;i++){
scanf("%d%d",&p[i].x,&p[i].y);
p[i].id=i;
}
sort(p+1,p+m+3,cmp1);
for (int i=1;i<=m+1;i++)
if (p[i].x==p[i+1].x)
add(p[i].id,p[i+1].id,(long long)(p[i+1].y-p[i].y)*2);
sort(p+1,p+m+3,cmp2);
for (int i=1;i<=m+1;i++)
if (p[i].y==p[i+1].y)
add(m+2+p[i].id,m+2+p[i+1].id,(long long)(p[i+1].x-p[i].x)*2);
sort(p+1,p+m+3,cmp3);
for (int i=1;i<=m;i++)add(i,i+m+2,1);
add(m+1,m+1+m+2,0);
spfa(m+1);
cout<<min(dis[m+2],dis[m+2+m+2]);
}