51nod 1443 路径和树(最短路)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1443
题目来源: CodeForces
基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
给定一幅无向带权连通图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
题解:开始想着先求最短路再求一次最小生成树,,,后来发现只要在求最短路时记录最小前驱边权就行...
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 300005; 4 const int M = 300005; 5 typedef long long ll; 6 const ll INF = 1e18; 7 struct edge { 8 int to; 9 ll cost; 10 edge(int _to, ll _cost):to(_to),cost(_cost){} 11 }; 12 typedef pair<ll, int> P;// first是最短距离,second是顶点的编号 13 int V; 14 vector<edge>G[N]; 15 ll d[N]; 16 ll pre[N]; 17 void dij(int s) { 18 priority_queue<P, vector<P>, greater<P> > que; 19 for(int i = 0; i <= V; ++i) d[i] = INF; 20 d[s] = 0; 21 que.push(P(0, s)); 22 23 while(!que.empty()) { 24 P p = que.top(); que.pop(); 25 int v = p.second; 26 if(d[v] < p.first) continue; 27 int num = G[v].size(); 28 for(int i = 0; i < num; ++i) { 29 edge e = G[v][i]; 30 if(d[e.to] > d[v] + e.cost) { 31 pre[e.to] = e.cost; 32 d[e.to] = d[v] + e.cost; 33 que.push(P(d[e.to], e.to)); 34 } 35 else if(d[e.to] == d[v] + e.cost) { 36 pre[e.to] = min(pre[e.to], e.cost); 37 } 38 } 39 } 40 } 41 42 int main() { 43 int n, m, i, j, u, v, st; 44 ll w; 45 memset(pre, 0, sizeof(pre)); 46 scanf("%d%d", &n, &m); 47 V = n; 48 while(m--) { 49 scanf("%d%d%lld", &u, &v, &w); 50 G[u].push_back(edge(v, w)); 51 G[v].push_back(edge(u, w)); 52 } 53 scanf("%d", &st); 54 dij(st); 55 ll ans = 0; 56 //最小前驱边权和 57 for(i = 1; i <= n ;++i) { 58 ans += pre[i]; 59 } 60 printf("%lld\n", ans); 61 return 0; 62 }