给定一个无向网,求最小权差生成树的权差
题目
问题描述:
最小生成树(MST)是图论中一个常见而简单的问题。本题要求的最小权差生成树比MST更难一些。
给定一个无向网,以及它的一棵生成树。定义该生成树的权差为:权值最大的边 – 权值最小的边。
给定一个无向网,求最小权差生成树的权差。
输入描述:
输入文件中包含多个测试数据。输入文件第一行为一个正整数T,为测试数据的个数。
每个测试数据描述了一个无向网,第一行为两个正整数n和m,2<n≤200,m≤5000,分别表示无向网中的顶点数和边数;接下来有m行,每行描述了一条无向边,为3个整数,u v w,0<u, v≤n(即顶点序号从1开始计起),0<w≤100 000 000,表示一条连接顶点u和v的无向边,权值为w。任何两个顶点间最多只有一条边相连。无向网是连通的,且任何两个顶点之间最多只有一条边。
输出描述:
对输入文件中的每个测试数据,输出求得的最小权差生成树的权差。
样例输入: | 样例输出: |
---|---|
1 3 3** 1 2 10 1 3 20 **2 3 30 | 10 |
CODE
#include<iostream>
#include<algorithm>
#define MAXN 105
#define MAXM 10005
#define INF 1000000000//定义无限大
using namespace std;
int n, m;
int fa[MAXN];
struct node
{
int x, y, w;
bool operator <(const node& a) const {
return w < a.w;//根据边的权重有小到大排序
}
}e[MAXM];
int find(int x)
{
if (fa[x] == x) return x;
int t = find(fa[x]);//压缩路径
fa[x] = t;
return t;
}
int main()
{
int nn;
scanf("%d", &nn);
for (int ii = 0; ii < nn; ii++) {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; ++i)
scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].w);//存储边
sort(e, e + m);//根据权重排序
int ans = INF;
for (int i = 0; i <= m - n + 1; i++) {//多次更新最小生成树
int tmp = -1, sum = 0;
for (int j = 1; j <= n; ++j) fa[j] = j;//初始化,每个点都是单独一个集合
for (int j = i; j < m; ++j) {
int tx = find(e[j].x), ty = find(e[j].y);
if (tx != ty) {
sum++;
fa[tx] = ty;
if (sum == n - 1) {
tmp = e[j].w - e[i].w;
break;
}
}
}
if (tmp != -1 && tmp < ans) ans = tmp;
}
if (ans < INF) printf("%d\n", ans);
else printf("-1\n");
}
return 0;
}