Luogu P3831 [SHOI2012]回家的路
分层最短路。
可以发现,需要做出选择的地方只有地铁站,所以点集就是所有地铁站。
所有相同x坐标地铁站之间纵向连边,点编号1~n,y相同地铁站之间纵向连边,编号n+1~2n,
边权为x或y坐标差值*2。
在每个地铁站可以选择换乘或者不换乘,如果换乘,花费为1,坐标由i变成i+n(或i-n)。
所以,在每个地铁站i与i+n之间连双向边,边权为1.
跑最短路即可w
代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MogeKo qwq #include<queue> #include<algorithm> using namespace std; const int maxn = 1e7; const int INF = 0x3f3f3f3f; int n,m,s,t; int head[maxn],to[maxn],nxt[maxn],val[maxn]; int dis[maxn],cnt; bool vis[maxn]; struct node { int id,x,y; } a[maxn]; bool cmpx(node A,node B) { return A.x < B.x || ((A.x == B.x) && A.y < B.y); } bool cmpy(node A,node B) { return A.y < B.y || ((A.y == B.y) && A.x < B.x); } void add(int x,int y,int z) { to[++cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; val[cnt] = z; } void init() { for(int i = 0; i <= n+n; i++) dis[i] = INF; } void dijkstra(int s) { init(); 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 = nxt[i]) { int v = to[i]; if(dis[u] + val[i] < dis[v]) { dis[v] = dis[u] + val[i]; q.push(make_pair(dis[v],v)); } } } } int main() { scanf("%d%d",&n,&m); n = m+2; s = n-1,t = n; for(int i = 1; i <= n; i++) { scanf("%d%d",&a[i].x,&a[i].y); a[i].id = i; } add(s,s+n,0); add(s+n,s,0); add(t,t+n,0); add(t+n,t,0); for(int i = 1; i <= n-2; i++) { add(i,i+n,1); add(i+n,i,1); } sort(a+1,a+n+1,cmpx); for(int i = 1; i < n; i++) { if(a[i].x != a[i+1].x)continue; add(a[i].id,a[i+1].id,(a[i+1].y-a[i].y)*2); add(a[i+1].id,a[i].id,(a[i+1].y-a[i].y)*2); } sort(a+1,a+n+1,cmpy); for(int i = 1; i < n; i++) { if(a[i].y != a[i+1].y)continue; add(a[i].id+n,a[i+1].id+n,(a[i+1].x-a[i].x)*2); add(a[i+1].id+n,a[i].id+n,(a[i+1].x-a[i].x)*2); } dijkstra(s); printf("%d\0",dis[t]); return 0; }