码迷,mamicode.com
首页 > 其他好文 > 详细

1395 - Slim Span (最小生成树)

时间:2015-08-16 19:48:25      阅读:113      评论:0      收藏:0      [点我收藏+]

标签:

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;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

1395 - Slim Span (最小生成树)

标签:

原文地址:http://blog.csdn.net/weizhuwyzc000/article/details/47704895

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!