思路:
对于本题而言:n个点,k条边的无向图,连线之间权值越小越好,要求我们删除回路里,权值更大的边。然后求出所有删除的边的权值总和。
而我们的最小生成树算法:求的是连通路的最小权值总和。而本题要求的是最大权值和。
所以我们需要往最小生成树上转化。
给定了图,数据范围是稀疏图 – 首先排除的是邻接矩阵 – prime算法。
其次是对于边的选取,如果采用Kruskal算法,是将边从小到大排序的,那么这就恰好迎合了题意,从小到大利用边去连通两个点,当你遇到某条边上的两个点是已经连通了的,说明这两个点之间存在回路,由于是从小到大枚举每条边,所以此时发现的回路边自然更大,那么由题意可知,此时就是回路中所需要删除的权值更大的边在回路状态下。
故累计该边的权值即可。其他的按照Kruskal算法连接就行了。只需要加个特判处理。
代码:
Kruskal算法不会受到连通块的影响。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e2 + 10, M = 2e2 + 10;
struct Edge{
int a, b, c;
bool operator < (const Edge& E) const{
return c < E.c;
}
}edge[M];
int n, k, p[N];
int find (int x)
{
if (x != p[x])
p[x] = find(p[x]);
return p[x];
}
int kruskal()
{
int res=0;
for (int i=1; i <= n; i++) p[i] = i;
sort (edge+1, edge+1+k);
for (int i=1; i <= k; i ++) //遍历边!
{
int a = edge[i].a, b = edge[i].b, w = edge[i].c;
a = find(a), b = find(b);
if (a != b)
{
p[a] = p[b];
}
else res += w;
}
return res;
}
int main()
{
cin >> n >> k;
for (int i=1; i <= k; i ++)
{
int a, b, c;
cin >> a >> b >> c;
edge[i] = {a, b, c}; //存边!
}
cout << kruskal ();
return 0;
}
prime算法: