1. 程式人生 > >【最短路徑樹】51nod1443 路徑和樹

【最短路徑樹】51nod1443 路徑和樹

註意 產生 並不是 opera ges getchar() 分析 ont end

並不是什麽高端操作並且一些模型會用到

Description

給定一幅無向帶權連通圖G = (V, E) (這裏V是點集,E是邊集)。從點u開始的最短路徑樹是這樣一幅圖G1 = (V, E1),其中E1是E的子集,並且在G1中,u到所有其它點的最短路徑與他在G中是一樣的。

現在給定一幅無向帶權連通圖G和一個點u。你的任務是找出從u開始的最短路徑樹,並且這個樹中所有邊的權值之和要最小。

Input

單組測試數據。
第一行有兩個整數n和m(1 ≤ n ≤ 3*10^5, 0 ≤ m ≤ 3*10^5),表示點和邊的數目。
接下來m行,每行包含3個整數 ui, vi, wi ,表示ui和vi之間有一條權值為wi的無向邊(1 ≤ ui,vi ≤ n, 1 ≤ wi ≤ 10^9)。
輸入保證圖是連通的。
最後一行給出一個整數u (1 ≤ u ≤ n),表示起點。

Output

輸出這棵樹的最小的權值之和。

Input示例

3 3
1 2 1
2 3 1
1 3 2
3

Output示例

2

題目大意

求最短路徑樹的最小權值和

題目分析

最短路徑樹是原圖的一種生成樹。註意以不同的點為根產生的最短路徑樹是不一樣的(道理同最短路)。

這裏要求的是“最小權值和”,聽上去好像很麻煩的樣子:要把跑的最短路的邊拎出來,再做一遍最小生成樹……

但是實際上我們發現它是滿足貪心性質的,並且並不會影響後面元素的取值。

所以只需要維護一個$pre[i]$表示轉移到$i$的最小邊權,然後在dij過程中再加一句判斷就可以了。

來自hzq的告誡:“能用堆優化dij就用堆優化的dij,SPFA盡量盡量不要寫。系統堆優化的dij有這麽難寫嗎?”

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 const int maxn = 300035;
 4 const int maxm = 600035;
 5 const ll INF = 1152921504606846976;
 6 
 7 ll dis[maxn],pre[maxn],ans;
 8 struct cmp
 9 {
10     bool operator
()(int a, int b) const 11 { 12 return dis[a] > dis[b]; 13 } 14 }; 15 struct Edge 16 { 17 int y; 18 ll val; 19 Edge(int a=0, ll b=0):y(a),val(b) {} 20 }edges[maxm]; 21 int n,m,s; 22 int head[maxn],nxt[maxm],edgeTot; 23 std::priority_queue<int, std::vector<int>, cmp> q; 24 25 int read() 26 { 27 char ch = getchar(); 28 int num = 0; 29 bool fl = 0; 30 for (; !isdigit(ch); ch = getchar()) 31 if (ch==-) fl = 1; 32 for (; isdigit(ch); ch = getchar()) 33 num = (num<<1)+(num<<3)+ch-48; 34 if (fl) num = -num; 35 return num; 36 } 37 void addedge(int u, int v, ll w) 38 { 39 edges[++edgeTot] = Edge(v, w), nxt[edgeTot] = head[u], head[u] = edgeTot; 40 } 41 int main() 42 { 43 memset(head, -1, sizeof head); 44 n = read(), m = read(); 45 for (int i=1; i<=m; i++) 46 { 47 int u = read(), v = read(), w = read(); 48 addedge(u, v, w), addedge(v, u, w); 49 dis[i] = INF; 50 } 51 s = read(), q.push(s), dis[s] = 0; 52 while (q.size()) 53 { 54 int tt = q.top(); 55 q.pop(); 56 for (int i=head[tt]; i!=-1; i=nxt[i]) 57 { 58 int v = edges[i].y; 59 ll w = edges[i].val; 60 if (dis[v] > dis[tt]+w||(dis[v]==dis[tt]+w&&pre[v] > w)) 61 dis[v] = dis[tt]+w, pre[v] = w, q.push(v); 62 } 63 } 64 for (int i=1; i<=n; i++) 65 ans += pre[i]; 66 printf("%lld\n",ans); 67 return 0; 68 }

END

【最短路徑樹】51nod1443 路徑和樹