Uva1395.Slim Span(最小生成树变形)

来源:互联网 发布:微信三公软件 编辑:程序博客网 时间:2024/06/07 04:47

Description

给出n个点(n100),m条边,求出最大边减最小边差值最小的生成树

Solution

首先可以注意到n不是很大,最大只有100,自然而然想到的就是暴力的做法。

将边按权值从小到大排序。在排好序的边中枚举[L,R]区间内的边,判断是否能形成最小生成树,若可以,则当前的差值就为e[R].we[L].w

可以注意到,对于枚举R的范围内,已经是最优的,因为当R继续增大时,对应权值也会增大,此时结果不会最优。所以可以跳出循环。但是并不意味着是全局最优的,因此还需要继续枚举L。

Code

#include<bits/stdc++.h>#define ll long long#define nmax 10000+5#define nume 105using namespace std;struct edg{    int f,t,w;}e[nmax];int fa[nume];int n,m,ans = 100000000;void makeset(int x){    fa[x] = x;}int findset(int x){    int rt = x, temp;    while(fa[rt] != rt) rt=fa[rt];    while(x!=rt){        temp = fa[x];        fa[x] = rt;        x = temp;    }    return rt;}int unionset(int x ,int y){    x = findset(x);    y = findset(y);    if(x == y) return -1;    else{        fa[x] = y;        return 0;    }}bool cmp(edg a, edg b){    if(a.w<b.w) return true;    else if(a.w == b.w){        return a.f < b.f;    }else return false;}void kur(){    int num = n;    int sta = 0,ed = 0;    for(int i = 0;i<m;++i){        for(int j = i;j<m;++j){            num = n;            sta = e[i].w,ed=e[j].w;            for(int k = i;k<=j;++k){                if(unionset(e[k].f,e[k].t)!=-1){                    num--;                }            }            for(int i = 1;i<=n;++i) makeset(i);            if(num == 1){                ans = min(ed - sta,ans);                break;            }        }    }}int main(){    while(scanf("%d %d",&n,&m) != EOF){        if(n == 0 && m == 0) break;        ans = 100000000;        for(int i = 1;i<=n;++i) makeset(i);        for(int i = 0;i<m;++i){            scanf("%d %d %d",&e[i].f,&e[i].t,&e[i].w);        }        sort(e,e+m,cmp);        kur();        if(ans == 100000000) printf("-1\n");        else printf("%d\n",ans);    }    return 0;}