NOIP模擬 有向無環圖(玄學建圖+最短路)
阿新 • • 發佈:2018-12-18
內網傳送門
【題目分析】
SPFA竟然有人亂搞A了?orz(蒟蒻亂搞只有40pts qwq)
很巧妙的建圖思路,將每條路徑視為一個點,從一條路徑i到達另一條路徑j,如果w[i]<w[j],那麼會產生w[j]-w[i]的費用,否則不會產生任何費用。
所以考慮將所有邊存下,然後每個點遍歷一遍,將邊排序,從小到大依次加費用為0的邊,再從大到小加費用為w[i]-w[i-1]的邊,最後在圖上跑迪傑斯特拉即可。
【程式碼~】
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,int> pii; const int MAXN=2e5+50; const int MAXM=4e5+50; int n,m,ecnt=1; int head[MAXN],vis[MAXM],tot; int nxt[MAXM],to[MAXM],w[MAXM]; ll dis[MAXM]; vector<pii>edge[MAXM]; priority_queue< pii,vector<pii>,greater<pii> >q; struct Edge{ int id,w; Edge(){} Edge(int x,int z):id(x),w(z){} friend inline bool operator <(const Edge &a,const Edge &b){ return a.w<b.w; } }e[MAXM]; int Read(){ int i=0,f=1; char c; for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0'; return i*f; } void add(int x,int y,int z){ nxt[++ecnt]=head[x]; head[x]=ecnt; to[ecnt]=y; w[ecnt]=z; } void dijkstra(){ for(int i=2;i<=ecnt;i++) dis[i]=2e18; for(int i=head[1];i;i=nxt[i]){ dis[i]=w[i]; q.push(make_pair(dis[i],i)); } while(!q.empty()){ if(vis[q.top().second]){ q.pop(); continue; } int u=q.top().second; q.pop(); vis[u]=1; for(int i=edge[u].size()-1;i>=0;i--){ int v=edge[u][i].first; int w=edge[u][i].second; if(vis[v]) continue; if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; q.push(make_pair(dis[v],v)); } } } } int main(){ n=Read(),m=Read(); for(int i=1;i<=m;i++){ int x=Read(),y=Read(),z=Read(); add(x,y,z);add(y,x,z); } for(int u=2;u<n;u++){ tot=0; for(int i=head[u];i;i=nxt[i]) e[++tot]=Edge(i,w[i]); sort(e+1,e+tot+1); for(int i=1;i<=tot;i++){ if(i!=1) edge[e[i].id].push_back(make_pair(e[i-1].id,0)); if(i!=tot) edge[e[i].id].push_back(make_pair(e[i+1].id,e[i+1].w-e[i].w)); edge[e[i].id^1].push_back(make_pair(e[i].id,e[i].w)); } } dijkstra(); ll ans=2e18; for(int i=head[n];i;i=nxt[i]) ans=min(ans,dis[i^1]+w[i]); cout<<ans; return 0; }