标签:
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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/weizhuwyzc000/article/details/47704895