欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > c/c++ >内容正文

c/c++

CSP认证201609-4交通规划[C++题解]:最短路径树、dijkstra求单源最短路、递推思想

发布时间:2025/4/5 c/c++ 39 豆豆
生活随笔 收集整理的这篇文章主要介绍了 CSP认证201609-4交通规划[C++题解]:最短路径树、dijkstra求单源最短路、递推思想 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

题目分析


来源:acwing

分析: 这题是最短路树。保持原图中所有点到根结点的最短距离不变,然后在原图中选择一些边,使所有点连通的最短路是多长。

最短路径树,是一种使用最短路径算法生成的数据结构树。
定义
考虑一个连通无向图G,一个以顶点v为根节点的最短路径树T是图G满足下列条件的生成树——树T中从根节点v到其它顶点u的路径距离,在图G中是从v到u的最短路径距离。

来源:维基百科

在这个生成树上的两点a和b,如果a能通过b点到达根结点,那么有一个等式d[b]=d[a]+wa−>bd[b] = d[a] + w_{a->b}d[b]=d[a]+wa>b,其中d[b]d[b]d[b]d[a]d[a]d[a]表示该点到根的距离,wa−>bw_{a->b}wa>b表示a到b的距离。

既然有了这个等式,其实每个点到根结点的路径的选项就有限了,因为该点到根的最小距离可以求出来,该点通过其他点到根结点一定满足上面的等式,所以我们可以预处理出来可行的通路!做法是dijkstra求每个点的最短路,然后遍历除根之外的所有点,看看它们的邻边有哪些是满足上面这个等式的。

其实,上面等式还说明了另一个问题,就是d[a] 一定比d[b]小,因为边权都是正的,这就启发我们将单源最短路的点从小到大排序,从小到大开始查看是否满足这个等式,满足的可以和根结点形成树!

我们假设f(i)表示把前i个点合法挂到根结点所需要的总代价。
在挂第i个点的时候,只有几个点满足上述等式(我们称之为备选边),
所以有 f(i)=min[f(i−1)+w(被选点→i)]f(i) = min[f(i-1) + w(被选点\rightarrow i)]f(i)=min[f(i1)+w(i)]

到这一步,这里公共的是f(i-1),我们只需要求出最小的w(某点->i点)即可。

所以,我们最后求的答案就是不断从根的邻点遍历,求出每个点权值最小的边(该点需要满足d[b]=d[a]+wa−>bd[b] = d[a] + w_{a->b}d[b]=d[a]+wa>b这个等式)

所以,核心代码如下

for(int a = 2; a <= n; a ++){int minw = INF; // 遍历所有的邻点for(int j = h[a]; ~j; j = ne[j]){int b= e[j];if(dist[a] == dist[b] + w[j])minw = min(minw, w[j]);}res += minw; // 每个点找到权值最小的边}

AC代码

#include<bits/stdc++.h> #define x first #define y second using namespace std; typedef pair<int, int> PII; const int N = 10010, M = 200010, INF = 0x3f3f3f3f;int dist[N]; bool st[N];int n, m; int h[N], e[M],ne[M], w[M], idx;void add(int a, int b, int c){e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++; }// 求根到所有点的最短路 void dijkstra(){memset(dist, 0x3f, sizeof dist);dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>> heap;heap.push({0, 1});while(heap.size()){auto t = heap.top();heap.pop();int ver = t.y, distance = t.x;if(st[ver]) continue;st[ver] = true;for(int i = h[ver]; ~i; i = ne[i]){int j = e[i];if(dist[j] > distance + w[i]){dist[j] = distance + w[i];heap.push({dist[j], j});}}}}int main(){cin >> n >> m;memset(h, -1, sizeof h);while(m --){int a, b, c;cin >> a >> b >> c;add(a, b, c), add( b, a, c);}dijkstra();// int res = 0;for(int a = 2; a <= n; a ++){int minw = INF;// 遍历所有的邻点for(int j = h[a]; ~j; j = ne[j]){int b= e[j];// 根到a的距离 == 根到b的距离 + a到b的距离if(dist[a] == dist[b] + w[j])minw = min(minw, w[j]);}res += minw;}cout << res << endl; }

题目链接

总结

以上是生活随笔为你收集整理的CSP认证201609-4交通规划[C++题解]:最短路径树、dijkstra求单源最短路、递推思想的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。