1. 程式人生 > 其它 >最小生成樹演算法Kruskal

最小生成樹演算法Kruskal

目錄

最小生成樹演算法

最小樹定義:

  • 給定網路\(G=(N,E,W)\),設\(T=(N,E')\)\(G\)的一個支撐樹,令\(W(T)=\sum_{e\in E'}W(e)\)\(T\)的權(或長)。\(G\)中權最小的支撐樹稱為\(G\)最小樹

1、Kruskal

  • 並查集:用一個元素代表一組元素,用於查詢不同元素是否屬於同一組,以及合併組
    int par[MAXN];//每個元素所在集合代表元素的編號
    int rnk[MAXN];//所在集合的大小;
    //初始化
    for(int i=0; i<n; i++){
        par[i]=i;  
        rnk[i]=1;
    }  
    int find(int x){
      //查詢x所在集合的代表元
      if(par[x]==x)//到達根
        return x;
      //直接路徑壓縮,忽略節點之間關係,把節點掛到根上
      else par[x] = find(par[x]);
    }
    bool unite(int x,int y){
      //把一個分組掛到另一個分組,返回合併是否成功
      x=find(x);
      y=find(y);
      if(x == y) return false;
      if(rnk[x]>rnk[y]){//把小樹掛在大樹上,防止出現高樹
          par[y]=x;
          rnk[x] = (rnk[y] += rnk[x]);
          //可以直接rnk[x]+=rnk[y]
      }
      else{
          par[x]=y;
          rnk[y] = (rnk[x] += rnk[y]);
          //可以直接rnk[y]+=rnk[x]
      }
      return true;
    }
    

1.1 演算法簡介

Kruskal是1956年首次提出的求最小生成樹的演算法,後來Edmonds把該演算法稱為貪心演算法,其基本思路就是從G中的m條邊中選取n-1條權儘可能小的邊,使其不構成迴路,從而構成一個最小樹。

  • 第一步:把圖按照邊權的大小從小到大排列起來,初始化一個已選中的邊集,或計數器
  • 第二步:不斷從加入之後不構成環的邊中選擇權最小的邊加入邊集
  • 第三步:如果邊集中邊的數量達到n-1,則停止,否則繼續選邊加邊

1.2 C++實現

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6;
struct edge{
    int u,v,w;
    //過載比較符,為了按照邊權排序
    bool operator < (const edge& t){
        return w < t.w;
    }  
}e[MAXN];
int m,n;
int par[MAXN];//每個元素所在集合代表元素的編號
int rnk[MAXN];//所在集合的大小;

void init(int n){
    for(int i=0; i<n; i++)
        par[i]=i; 
}

int find(int x){
    if(par[x]==x) return x;
    else par[x] = find(par[x]);
}

bool unite(int x,int y){
    x=find(x);y=find(y);
    if(x == y) return false;
    par[x]=y;
    return true;
}

int kruskal(){
    std::sort(e+1,e+1+m);
    int cnt=0,minum_tree_size=0;
    for(int i=1; i<=m; i++){
        if(unite(e[i].u,e[i].v)){
            minum_tree_size += e[i].w;
            if(++cnt == n-1)break; 
        }
    }
    return cnt==n-1? ans : -1;
}

int main(){
    scanf("%d%d", &m,&n);
    init(n);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    printf("%d\n",kruskal())
    return 0;
}
祝看到這裡的你生活愉快,謝謝