poj3522

题意:给点一个无向图,求一个生成树使树中最大边与最小边的差的最小。

分析:并查集。把所有边排序,然后从小到大看,每次枚举一个边,将其权值作为下界,向右寻求一个上界,让上下界之间的边可以使得图连通。寻求过程中,是每次将一个边加入图中,判断图是否连通,不行则再加一条边,判断过程用并查集。找到没个下界对应的上界,找上下界差的最小值。

View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 105, maxm = maxn * maxn / 2, inf = 0x3f3f3f3f;

struct Edge
{
    int a, b, w;
}edge[maxm];

int n, m;
int father[maxn];

bool operator < (const Edge &a, const Edge &b)
{
    return a.w < b.w;
}

void input()
{
    for (int i = 0; i < m; i++)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        a--;
        b--;
        edge[i].a = a;
        edge[i].b = b;
        edge[i].w = w;
    }
}

int getanc(int a)
{
    if (a == father[a])
        return a;
    return father[a] = getanc(father[a]);
}

int cal(int l)
{
    for (int i = 0; i < n; i++)
        father[i] = i;
    int i = l;
    int block_num = n;
    while (i < m && block_num > 1)
    {
        int a = getanc(edge[i].a);
        int b = getanc(edge[i].b);
        if (a != b)
        {
            block_num--;
            father[a] = b;
        }
        i++;
    }
    if (block_num > 1)
        return -1;
    return edge[i - 1].w - edge[l].w;
}

void work()
{
    int ans = cal(0);
    if (ans == -1)
    {
        printf("-1\n");
        return;
    }
    for (int i = 1; i < m; i++)
    {
        if (edge[i].w == edge[i - 1].w)
            continue;
        int temp = cal(i);
        if (temp == -1)
            break;
        ans = min(ans, temp);
    }
    printf("%d\n", ans);
}

int main()
{
    //freopen("t.txt", "r", stdin);
    while (scanf("%d%d", &n, &m), n | m)
    {
        memset(edge, -1, sizeof(edge));
        input();
        sort(edge, edge + m);
        work();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/rainydays/p/2574314.html