1395 - Slim Span (最小生成树)

UVA上的题就是让人眼前一亮,不同于那些赤裸裸的生成树水题,该题稍加了变化,不是求最小生成树,而是求最苗条生成树 。  

因为生成树有很多,而且每一棵生成树的最大边与最小边只差也是不确定的 。所以只能枚举所有的生成树 。

套用最小生成树模板 ,我们可以枚举生成树的起点位置,然后向后推终点位置,当n个点全部连通时,那么这棵生成树的边集就是[L,R] 。因为边事先都排好序了, 那么该树的苗条值就是e[R] - e[L] 。

这样从小到大枚举所有的L ,不断更新答案,就可以了 。

忍不住再说一下并查集,这是一个很厉害的数据结构, 其效率非常高,在平摊意义下,find函数的时间复杂度几乎可以看成是常数, 而union显然也是常数时间 。 

其精彩之处在于那个很短的路径压缩(find函数), 《挑战》上还用了一个rank函数来进一步优化,不过对于时间紧张的比赛来说,完全可以省略,只写少量的代码即可。

细节参见代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
const int INF = 1000000000;
const int maxm = maxn * (maxn - 1) /2;
int n,m,p[maxn];
struct node{
    int a,b,v;
}e[maxm];
bool cmp(node a,node b) {
    return a.v < b.v;
}
int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
int solve() {
    int ans = INF;
    for(int L=0;L<m;L++) {
        for(int i=1;i<=n;i++) p[i] = i; //初始化并查集
        int cur = 1;
        for(int R=L;R<m;R++) {
            int x = find(e[R].a) , y = find(e[R].b);
            if(x != y) { p[x] = y; cur++; }
            if(cur == n) {
                ans = min(ans,e[R].v - e[L].v); break;
            }
        }
        if(cur != n) break; //如果该起点L不符合要求,那么接下来的也不符合 。
    }
    return ans;
}
int main() {
    while(~scanf("%d%d",&n,&m)) {
        if( !n && !m ) return 0;
        for(int i=0;i<m;i++) scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].v);
        sort(e,e+m,cmp);
        int ans = solve();
        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、付费专栏及课程。

余额充值