POJ 3522 Slim Span (並查集 + 枚舉 + kruskal)

鏈接:點擊打開鏈接

題目好長, 而且還有圖片,所以就不復制粘貼過來了,這道題的大意是:

一棵樹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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章