【最短路径树】51nod1443 路径和树

并不是什么高端操作并且一些模型会用到

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
",ans);
67     return 0;
68 }

END

原文地址:https://www.cnblogs.com/antiquality/p/9301766.html