[UVA 1395]苗条的生成树

题意简述

求所有生成树中最大边权与最小边权差最小的,输出它们的差值。

显然我们随便跑一个Kruskal可以得到所有生成树中最大边权最小的边。但是最小边权不好保证。注意到n<=100,m <= (n - 1)n/2即m <= 4950,那就暴力一下。对边排好序后,从头枚举每条边作为最小生成树的第一条边,然后往后找边,跑出小于m个生成树,每跑出一个更新答案就行。

一次AC,时间复杂度O(m²),可以通过。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 210
#define M 10000000
using namespace std;
int n,m;
struct qwq
{
    int x,y,val;
    bool operator < (const qwq &a) const
    {
        return val < a.val;
    }
}e[M];
int fa[N],siz[N];
int find(int x)
{
    if(fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}
void merge(int x,int y)
{
    if(siz[x] > siz[y]) swap(x,y); 
    siz[y] += siz[x];
    fa[x] = y;
    return;
}
void pre_fa()
{
    for(int i = 1;i <= n;i++)
    {
        fa[i] = i;
        siz[i] = 1;
    }
    return;
}
int kruskal()
{
    sort(e + 1,e + 1 + m);
    int tot = 0,ans = 10000000;
    for(int j = 1;j <= m;j++)
    {
        pre_fa();
        tot = 0;
        int maxx = 0;
        for(int i = j;i <= m;i++)
        {
            int x = find(e[i].x),y = find(e[i].y);
            if(x != y)
            {
                merge(x,y);
                maxx = max(maxx,e[i].val);
                tot++;
            }
            if(tot == n - 1)
            {
                ans = min(maxx - e[j].val,ans);
                break;
            }
        }
    }
    if(ans == 10000000) return -1;
    else return ans;
}
using namespace std;
int main()
{
    while(1)
    {
        scanf("%d %d",&n,&m);
        if(n == m && n == 0) break;
        memset(e,0,sizeof(e));
        for(int i = 1;i <= m;i++) 
        {
            scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].val);
        }
        printf("%d
",kruskal());
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lijilai-oi/p/10939691.html