本文共 2701 字,大约阅读时间需要 9 分钟。
为了解决这个问题,我们需要找到一种方法,使得在给定的点和额外边的条件下,连接所有点的总代价最小。我们可以使用Kruskal算法来解决这个问题,因为它适合处理稀疏图。
问题分析:我们需要连接所有的点,使得任意两点之间的代价最小。每个点有一个权值,原图中每个点对之间有一条边,边的权值是两个点的权值之和。我们还可以选择额外的边来替代这些边,从而降低总代价。
关键思路:找到权值最小的点t,将其他所有点连接到t。这样,连接t到其他点的边的权值是最小的。然后,剩下的边选择权值最小的边来连接其他点。
算法选择:使用Kruskal算法来找到最小生成树。Kruskal算法适合处理稀疏图,时间复杂度为O(m log m),适合处理大规模数据。
实现步骤:
题意:
n个点,每个点有一个权值node[i],在第i个点和第j个点之间连无向边的代价为node[i]+node[j],有m条额外边可选择,第u个点和第v个点连无向边的代价为w,额外边可以用可以不用。问连边使任意两点可连通的总代价是多少。
数据范围:1 ≤ n ≤ 2e5 , 0 ≤ m ≤ 2e5。
题解:
1. 使用Kruskal算法求最小生成树。
2. 找到权值最小的点t,将除t之外的点和t相连,原有的边与m条额外边共同组成可选的边集合E。
3. n ≤ 2e5,由于边是无向的且包括原有的边和额外边,总边数cnt ≤ 8e5,远小于2e5 * 2e5,是稀疏图,使用Kruskal算法。
4. Prim算法复杂度O(n²)不适合,Kruskal算法复杂度O(m log m)适合。
#include#define N 800005 using namespace std; int n, m, cnt = 0; long long node[N]; int pre[N]; struct Edge { int u, v; long long weight; }; int find(int x) { if (x == pre[x]) return pre[x]; pre[x] = find(pre[x]); return pre[x]; } bool cmp(const Edge &a, const Edge &b) { return a.weight < b.weight; } void kruskal() { int i, j; int u, v; int ru, rv; long long sum = 0; sort(edges, edges + cnt, cmp); for (i = 0; i < cnt; ++i) { u = edges[i].u; v = edges[i].v; ru = find(u); rv = find(v); if (ru == rv) continue; pre[ru] = rv; sum += edges[i].weight; } cout << sum << endl; } int main() { int i, j; Edge a; scanf("%d%d", &n, &m); for (i = 1; i <= n; ++i) { scanf("%lld", &node[i]); if (node[i] < min_node) { min_node = node[i]; t = i; } pre[i] = i; } for (i = 1; i <= n; ++i) { if (i == t) continue; a.u = t; a.v = i; a.weight = node[t] + node[i]; edges[cnt++] = a; a.u = i; a.v = t; edges[cnt++] = a; } for (i = 1; i <= m; ++i) { scanf("%d%d%lld", &u, &v, &w); a.u = u; a.v = v; a.weight = w; edges[cnt++] = a; a.u = v; a.v = u; edges[cnt++] = a; } kruskal(); }
这个方法确保了在给定的约束条件下,连接所有点的总代价最小。
转载地址:http://bpml.baihongyu.com/