牛客國慶集訓派對Day3 I-Metropolis (迪傑斯特拉堆優化)
阿新 • • 發佈:2018-12-13
題目描述
魔方國有n座城市,編號為。城市之間通過n-1條無向道路連線,形成一個樹形結構。 在若干年之後,其中p座城市發展成了大都會,道路的數量也增加到了m條。 大都會之間經常有貿易往來,因此,對於每座大都會,請你求出它到離它最近的其它大都會的距離。
輸入描述:
第一行三個整數n,m,p (1 ≤ n,m ≤ 2*105,2 ≤ p ≤ n),第二行p個整數表示大都會的編號 (1≤ xi≤ n)。接下來m行每行三個整數ai,bi,li表示一條連線ai和bi,長度為li的道路 (1 ≤ ai,bi ≤ n,1 ≤ li ≤ 109)。 保證圖是連通的。
輸出描述:
輸出一行p個整數,第i個整數表示xi的答案。
示例1
輸入
5 6 3 2 4 5 1 2 4 1 3 1 1 4 1 1 5 4 2 3 1 3 4 3
輸出
3 3 5
解題思路:考慮暴力,求出兩點間的最短路徑,明顯不可取。但是題目只是要求某些點之間的最短路徑,考慮優化。我們從某一個要求的點出發,用迪傑斯特拉求最短路徑,第一個碰到的要求的點,就是該點的答案,我們記錄即可。我們對所有的點都做一遍這個操作,即可求得答案,但是這樣的複雜度感覺降低了(因為提前退出了迪傑斯特拉),實際上沒有降低。那麼我們考慮優化,我們用堆優化的迪傑斯特拉去求最短路,很容易就會想到,我們把所有要求的點在一開始就入隊,然後做一遍迪傑斯特拉即可,當碰到要求的點時我們更新最短路徑即可。這裡有兩種情況,一種是真的走到了要求的點,一種是走到了一半,這裡直接用染色的思想處理即可。
#include<iostream> #include<string.h> #include<queue> using namespace std; typedef long long ll; const int MAXN=2000005; const ll INF=0x3f3f3f3f3f3f3f3f; struct edge{ int u; int v; int w; int next; }e[MAXN]; int edge_num=0; int head[MAXN]; void insert_edge(int u,int v,int w){ e[edge_num].u=u; e[edge_num].v=v; e[edge_num].w=w; e[edge_num].next=head[u]; head[u]=edge_num++; } struct node{ int v; ll dis; node (ll a,int b):dis(a),v(b){}; bool operator <(const node &rhs)const { return dis > rhs.dis; } }; int N,M,K; bool vis[MAXN]; int P[MAXN]; ll d[MAXN]; ll ans[MAXN]; int belong[MAXN]; void dijkstra(){ priority_queue<node> que; memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); memset(ans,0x3f,sizeof(ans)); for(int i=0;i<K;i++) que.push(node(d[P[i]]=0,P[i])); while(!que.empty()){ node tp=que.top(); que.pop(); int u=tp.v; if(vis[u]) continue; vis[u]=1; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; int w=e[i].w; if(d[v]>d[u]+w)//如果碰到了,此條件必然不成立,因為初始為0 { d[v]=d[u]+w; que.push(node(d[v],v)); belong[v]=belong[u];//將從該點出發求最短路徑的過程都染色 }else if(belong[u]!=belong[v])//如果不同顏色就更新答案 { ans[belong[u]]=min(ans[belong[u]],d[u]+d[v]+w); ans[belong[v]]=min(ans[belong[v]],d[u]+d[v]+w); } } } } int main(){ scanf("%d%d%d",&N,&M,&K); edge_num=0; memset(head,-1,sizeof(head)); for(int i=0;i<K;i++){ scanf("%d",&P[i]); belong[P[i]]=P[i]; } int u,v,w; for(int i=0;i<M;i++){ scanf("%d%d%d",&u,&v,&w); insert_edge(u,v,w); insert_edge(v,u,w); } dijkstra(); for(int i=0;i<K;i++) printf("%lld ",ans[P[i]]); return 0; }