POJ 3522 Slim Span (并查集 + 枚举 + kruskal)

来源:互联网 发布:上海穷游住宿攻略知乎 编辑:程序博客网 时间:2024/05/16 19:16

链接:点击打开链接

题目好长, 而且还有图片,所以就不复制粘贴过来了,这道题的大意是:

一棵树T(连通无环子图)将用n-1条边连接原图的所有的n个顶点,生成的生成树的最大权值边与最小权值边的差(称“苗条值”)尽量小,找出这个最小的苗条值;


思路:

用kruskal枚举;

首先对每条边的权值从小到大进行排序;

枚举每条边为最小边生成最小生成树,并计算这样的生成树的苗条值,枚举玩所有的情况就可以求出苗条值;


代码解析如下:

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <stack>#include <queue>#include <map>#include <set>#include <cmath>#include <algorithm>#define MAXN 1000005#define RST(N)memset(N, 0, sizeof(N))using namespace std;typedef struct Edge_{    int x, y;    int rank;}Edge;Edge edge[MAXN];int n, m, res, Kc, father[MAXN];int cmp(const void *a, const void *b){    Edge *p1 = (Edge *)a;    Edge *p2 = (Edge *)b;    return p1->rank - p2->rank;}int find(int x)    //路径压缩寻找父节点{    return x == father[x] ? x : find(father[x]);}int solve(int x){    int cnt = 0;    for(int i=1; i<=n; i++) father[i]=i;    for(int i=x; i<m; i++) {       //kruskal试生成最小生成树;        int fx = find(edge[i].x);        int fy = find(edge[i].y);        if(fx != fy) {            father[fx] = fy;               cnt++;        }        if(cnt == n-1) return edge[i].rank-edge[x].rank;    }    return MAXN;}int main(){    while(~scanf("%d %d", &n, &m) && n || m) {        res = MAXN;        for(int i=0; i<m; i++) {            scanf("%d %d %d", &edge[i].x, &edge[i].y, &edge[i].rank);        }        qsort(edge, m, sizeof(Edge), cmp);   //权值从大到小;        for(int i=0; i<=m-n+1; i++) {     //从0 ~ m-(n-1)的范围枚举            res = solve(i) < res ? solve(i) : res;   //寻找最小差值;        }        if(res == MAXN) res = -1;    //不存在的话        printf("%d\n", res);    }    return 0;}


0 0