1. 程式人生 > >最小生成樹( Prim & Kruskal ) 模板加詳解

最小生成樹( Prim & Kruskal ) 模板加詳解

最小生成樹概念:

一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)演算法或prim(普里姆)演算法求出。最小生成樹其實是最小權重生成樹的簡稱。

prim:

概念:普里姆演算法(Prim演算法),圖論中的一種演算法,可在加權連通圖裡搜尋最小生成樹。意即由此演算法搜尋到的邊子集所構成的樹中,不但包括了連通圖裡的所有頂點,且其所有邊的權值之和亦為最小。

實現過程:

圖例 說明 不可選 可選 已選(Vnew)
 

此為原始的加權連通圖。每條邊一側的數字代表其權值。 - - -

頂點D被任意選為起始點。頂點ABEF通過單條邊與D相連。A是距離D最近的頂點,因此將A及對應邊AD以高亮表示。 C, G A, B, E, F D
 

下一個頂點為距離DA最近的頂點。BD為9,距A為7,E為15,F為6。因此,FDA最近,因此將頂點F與相應邊DF以高亮表示。 C, G B, E, F A, D
演算法繼續重複上面的步驟。距離A為7的頂點B被高亮表示。 C B, E, G A, D, F
 

在當前情況下,可以在C
EG間進行選擇。CB為8,EB為7,GF為11。E最近,因此將頂點E與相應邊BE高亮表示。
C, E, G A, D, F, B
 

這裡,可供選擇的頂點只有CGCE為5,GE為9,故選取C,並與邊EC一同高亮表示。 C, G A, D, F, B, E

頂點G是唯一剩下的頂點,它距F為11,距E為9,E最近,故高亮表示G及相應邊EG G A, D, F, B, E, C

現在,所有頂點均已被選取,圖中綠色部分即為連通圖的最小生成樹。在此例中,最小生成樹的權值之和為39。 A, D, F, B, E, C, G

演算法模板:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<string>
#include<cstring>
#include<set>
#include<cmath>
using namespace std;
#define PI acos(-1)
typedef long long LL;
#define inf 0x3f3f3f3f
const int maxn=1000+10;
int dis[maxn];
int vis[maxn];
int a[maxn][maxn];
int n,m;
void Prim()
{
    int ans=0;
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        dis[i]=a[1][i];
    dis[1]=0;
    vis[1]=1;
    int i;
    for(i=1;i<n;i++)
    {
        int minn=inf;
        int num=0;
        for(int j=1;j<=n;j++)
        {
            if(dis[j]<minn&&vis[j]==0)
            {
                minn=dis[j];
                num=j;
            }
        }
        if(minn==inf)
            break;
        vis[num]=1;
        ans+=minn;
        for(int j=1;j<=n;j++)
        {
            if(dis[j]>a[num][j]&&vis[j]==0)
                dis[j]=a[num][j];
        }
    }
    if(i<n)
        cout<<"?"<<endl;
    else
        cout<<ans<<endl;
    return ;
}
int main()
{
    while(cin>>m)
    {
        if(m==0)
            break;
        memset(a,inf,sizeof(a));
        cin>>n;
        for(int i=0;i<m;i++)
        {
            int x,y,z;
            cin>>x>>y>>z;
            if(z<a[x][y])
                a[x][y]=a[y][x]=z;
        }
        Prim();
    }
    return 0;
}

Kruskal演算法:

1.概覽

  Kruskal演算法是一種用來尋找最小生成樹的演算法,在剩下的所有未選取的邊中,找最小邊,如果和已選取的邊構成迴路,則放棄,選取次小邊。

2.實現過程

1).記Graph中有v個頂點,e個邊

2).新建圖Graphnew,Graphnew中擁有原圖中相同的e個頂點,但沒有邊

3).將原圖Graph中所有e個邊按權值從小到大排序

4).迴圈:從權值最小的邊開始遍歷每條邊 直至圖Graph中所有的節點都在同一個連通分量中  if 這條邊連線的兩個節點於圖Graphnew中不在同一個連通分量中   新增這條邊到圖Graphnew中

  圖例描述:

首先第一步,我們有一張圖Graph,有若干點和邊 

將所有的邊的長度排序,用排序的結果作為我們選擇邊的依據。這裡再次體現了貪心演算法的思想。資源排序,對區域性最優的資源進行選擇,排序完成後,我們率先選擇了邊AD。這樣我們的圖就變成了下圖

在剩下的變中尋找。我們找到了CE。這裡邊的權重也是5

依次類推我們找到了6,7,7,即DF,AB,BE。

下面繼續選擇, BC或者EF儘管現在長度為8的邊是最小的未選擇的邊。但是現在他們已經連通了(對於BC可以通過CE,EB來連線,類似的EF可以通過EB,BA,AD,DF來接連)。所以不需要選擇他們。類似的BD也已經連通了(這裡上圖的連通線用紅色表示了)。最後就剩下EG和FG了。當然我們選擇了EG。

程式碼:

複製程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m,sum;
struct node
{
    int start,end,power;//start為起始點,end為終止點,power為權值
} edge[5050];
int pre[5050];

int cmp(node a, node b)
{
    return a.power<b.power;//按照權值排序
}

int find(int x)//並查集找祖先
{
    if(x!=pre[x])
    {
        pre[x]=find(pre[x]);
    }
    return pre[x];
}

void merge(int x,int y,int n)//並查集合並函式,n是用來記錄最短路中應該加入哪個點
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        pre[fx]=fy;
        sum+=edge[n].power;
    }
}
int main()
{
    while(~scanf("%d", &n), n)//n是點數
    {
        sum=0;
        m=n*(n-1)/2;//m是邊數,可以輸入
        int i;
        int start,end,power;
        for(i=1; i<=m; i++)
        {
            scanf("%d %d %d", &start, &end, &power);
            edge[i].start=start,edge[i].end=end,edge[i].power=power;
        }
        for(i=1; i<=m; i++)
        {
            pre[i]=i;
        }//並查集初始化
        sort(edge+1, edge+m+1,cmp);
        for(i=1; i <= m; i++)
        {
            merge(edge[i].start,edge[i].end,i);
        }
        printf("%d\n",sum);
    }
    return 0;
}

複製程式碼

相關推薦

小生成樹 Prim & Kruskal 模板

最小生成樹概念: 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)演算法或prim(普里姆)演算法求出。最小生成樹其實是最小權重生成樹的簡稱。 p

小生成樹prim演算法模板

#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> usin

資料結構 第16講 溝通無限校園網——小生成樹prim演算法

本內容來源於本人著作《趣學演算法》,線上章節:http://www.epubit.com.cn/book/details/4825 校園網是為學校師生提供資源共享、資訊交流和協同工作的計算機網路。校園網是一個寬頻、具有互動功能和專業性很強的區域網絡。如果一所學校包括多個學院及部門,也可

無向圖小生成樹prim演算法

輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 - M + 1行:每行3個數

POJ-2031 小生成樹prim演算法

POJ-2031    Building a Space Station You are a member of the space station engineering team, and are assigned a task in the constructio

小生成樹Prim算法和Kruskal算法

under net 任務 合並 一個 心算 std fin details 1)最小生成樹 給定一個無向圖,如果它的某個子圖中任意兩個頂點都互相連通並且是一棵樹,那麽這棵樹就叫生成樹。如果邊上有權值,那麽使得邊權和最小的生成樹叫做最小生成樹(MST,Minimum Span

數學建模14——MATLAB實現小生成樹PrimKruskal演算法

Prim演算法 連通賦權圖如上 鄰接矩陣如下 0 50 60 0 0 0 0 0 0 0 65 4

小生成樹primkruskal

問題引入: 假設要在n個城市之間建立通訊網路,則連通n個城市至少需要n-1條線路。n個城市之間,最多可能設定n*(n-1)/2條線路。這時,自然會考慮一個問題:如何在這些可能的線路中選擇n-1條,使得在最節省費用的前提下建立該網路通訊? 解決方法:

c++資料結構與演算法之圖:鄰接矩陣、深度廣度遍歷、構造小生成樹primkruskal演算法

//圖的鄰接矩陣實現 //廣度遍歷bfs和深度遍歷dfs //構造最小生成樹的prim、kruskal演算法 #include <iostream> #include<stack> #include<queue> #define WEI

圖解:如何實現小生成樹Prim演算法與Kruskal演算法

![](https://user-gold-cdn.xitu.io/2020/7/16/17357262c89f3bf6?w=900&h=358&f=png&s=501010) > 這是圖演算法的第四篇文章 圖解:如何實現最小生成樹 文章目錄: - 1.概念和性質 - 2.

資料結構 筆記:小生成樹prim

運營商的挑戰 -在下圖標出的城市間架設一條通訊線路 要求: ·任意兩個城市間都能夠通訊 ·將架設成本呢將至最低   如何在圖中選擇n-1條邊使得n個頂點間兩兩可達,並且這n-1條邊的權值之和最小 最小生成樹 -僅使用圖中的n-1條邊連線圖中的n個頂點

prim小生成樹鄰接表

#include <iostream> #include <cstring> #include <vector> using namespace std; const

POJ 1258 : 小生成樹Prim

Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your hel

WUST 1944 短網路Agri-Net小生成樹prim演算法

1944: 最短網路Agri-Net Time Limit: 1 Sec  Memory Limit: 128 MB  64bit IO Format: %lldSubmitted: 22  Accepted: 9 [Submit][Status][Web Boar

P3366 【模板小生成樹boruvka/sollin

int fin targe http strong 合並操作 tdi 一個 ble P3366 【模板】最小生成樹 boruvka/sollin 復雜度$O(mlogn)$ 簡要說明一下過程 引入一個數組$link[i]$表示連通塊$i$下一步可更新的最短的邊的編號

小生成樹luogu 3366

無向圖 輸出 -o 題目 pac 數據 規模 nbsp 我們 題目描述 給出一個無向圖,求出最小生成樹 輸入輸出格式 輸入格式: 第一行包含兩個整數N、M,表示該圖共有N個結點和M條無向邊。(N<=5000,M<=200000) 接下來M行每行包含三個整數X

小生成樹資料結構

最小生成樹-Prim演算法和Kruskal演算法   Prim演算法 1.概覽 普里姆演算法(Prim演算法),圖論中的一種演算法,可在加權連通圖裡搜尋最小生成樹。意即由此演算法搜尋到的邊子集所構成的樹中,不但包括了連

資料結構實驗之圖論九:小生成樹 SDUT 2144

#include<bits/stdc++.h> using namespace std; typedef long long ll; struct node { int s, e; int w; }s[100005]; int c[105]; bool cmp(str

POJ 2395 Out of Hay 小生成樹prime演算法

題目: 有N(2-2000)個農場,M(1-10000)條通路連通各個農場,長度不超109,要求遍歷全部的農場,且每走1單位長度就要消耗一單位水,每到一個農場可以把自己的水充滿,求最小的水箱容量。 樣例輸入 3 3 1 2 23 2 3 1000 1 3 43 樣例輸

小生成樹算法prim+kruskal

span 實現 比較 info 開始 += width map end 最小生成樹概念: 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用kruskal(克魯斯卡爾)算法或prim(普