【最短路-拆點】ARC061Cすぬけ君の地下鉄旅行/Snuke's Subway Trip
阿新 • • 發佈:2020-11-05
題目解析
剛開始想的是分層圖,同個公司的邊是同一層。走的時候你可以在同一層隨便亂走,然後可以跑到另外一層的對應點去,這需要\(1\)的花費。
所以可以想到如下建邊方式:每一層之間的邊的邊權為\(0\),同一個點的任意兩層的點之間邊權為\(1\),即表示換乘的花費為\(1\)。
發現這樣建邊邊數會很多,比如一條邊在\(i\)層都出現過 那麼這個點就要建\(\frac {i(i-1)}{2}\)條邊。
可以整一個虛點把每一層的點都連在一起,相當於搞一個換乘站點出來。
每個點換乘到另一個層的點需要經過\(2\)條邊 所以每個點到換乘點的邊權為\(0.5\)
避免浮點運算 所以最後除以\(2\)
後來還發現了一種更加簡單暴力的方法:就是在做最短路的時候,判斷一下,如果前驅邊和這條邊的公司一樣,那麼費用就是\(0\),否則為\(1\)(記錄的東西變多了)不過這個我沒有寫qwq
►Code View
#include<cstdio> #include<algorithm> #include<iostream> #include<vector> #include<queue> #include<cstring> #include<ctime> #include<map> using namespace std; #define N 1000005 #define LL long long #define INF 0x3f3f3f3f #define inf 0x7fffffff int rd() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();} return f*x; } int n,m,s; int c[N],tot;//對公司編號進行離散化 vector<pair<int,LL> >G[N]; LL d[N]; priority_queue< pair<LL,int>, vector< pair<LL,int> >,greater<pair<LL,int> > >Q; map<pair<int,int>,int> mp;//編號為i的在第j個網路裡的點的編號 struct node{ int u,v,com; }e[N]; int iden;//點的編號 void Init() { while(!Q.empty()) Q.pop(); memset(d,0x7f,sizeof(d)); } void dijkstra() { Init(); d[s]=0;Q.push(make_pair(0,s)); while(!Q.empty()) { pair<LL,int> tmp=Q.top(); Q.pop(); int u=tmp.second; if(tmp.first>d[u]) continue; for(int i=0;i<G[u].size();i++) { int v=G[u][i].first; LL w=G[u][i].second; if(d[v]>d[u]+w) { d[v]=d[u]+w; Q.push(make_pair(d[v],v)); } } } } int ID(int x,int y) { if(mp.find(make_pair(x,y))!=mp.end()) return mp[make_pair(x,y)]; return mp[make_pair(x,y)]=++iden; } int main() { n=rd(),m=rd(); for(int i=1;i<=m;i++) { int u=rd(),v=rd(),id=rd(); if(!c[id]) c[id]=++tot; e[i].u=u,e[i].v=v,e[i].com=c[id]; } iden=n; for(int i=1;i<=m;i++) { int u=ID(e[i].u,e[i].com),v=ID(e[i].v,e[i].com); G[u].push_back(make_pair(v,0)); G[v].push_back(make_pair(u,0)); G[e[i].u].push_back(make_pair(u,1)); G[u].push_back(make_pair(e[i].u,1)); G[e[i].v].push_back(make_pair(v,1)); G[v].push_back(make_pair(e[i].v,1)); } s=1; dijkstra(); if(d[n]>=INF) puts("-1"); else printf("%lld\n",d[n]/2); return 0; }