POJ - 2395 Out of Hay(最小生成树)

题目链接:http://poj.org/problem?id=2395

题意:求一棵生成树使最大的边和最小的边差值最小。

思路:n很小,所以用kruskal直接从最小边开始枚举,一直往大的判断边,组成一棵生成树就停止,判断此时的差值,然后又从第二小的边开始往上遍历,重复操作。

这么做对的理由是因为排好了序,从小往大遍历使得枚举一次的结果一定是暂时最小的,那么从小到大依次枚举使得全部边都参与进来,所以所有暂时解的最小就是答案


代码:

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <numeric>
#include <set>
#include <string>
#include <cctype>
#include <sstream>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 1e2 + 5;

int n, m, p[maxn], q, cnt;
void init (int n) {
    for (int i = 0; i <= n; i++) p[i] = i;
}
int Find(int x) {
    return p[x] == x ? x : ( p[x] = Find ( p[x] ) );
}
bool same(int a, int b) {
    return Find(a) == Find(b);
}
void unite (int x, int y) {
    x = Find(x);
    y = Find(y);
    if (x != y)  p[x] = y;
}
struct edge {
    int u, v, cost;
} e[10005];
bool cmp(edge x, edge y) {
    return x.cost < y.cost;
}
int kruscal() {
    sort(e, e + cnt, cmp);
    int ans=INF;
    for (int j = 0; j <= cnt - n + 1; j++) {
        init(n);
        int num=0;
        for (int i = j; i < cnt; i++) {
            int x = Find(e[i].u), y = Find(e[i].v);
            if (x != y) {
                num++;
                unite(e[i].u, e[i].v);
                if (num==n-1){
                    ans=min(ans,e[i].cost-e[j].cost);
                    break;
                }
            }
        }
    }
    return ans;
}
int main() {
    while (~scanf ("%d%d", &n, &m)&&n) {
        cnt = 0;
        while (m--) {
            int u, v, cost;
            scanf ("%d%d%d", &u, &v, &cost);
            e[cnt].u = u;
            e[cnt].v = v;
            e[cnt++].cost = cost;
        }
        int ans = kruscal();
        if (ans==INF) printf ("-1\n");
        else printf ("%d\n", ans);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值