1. 程式人生 > >Kruskal/Prim最小生成樹

Kruskal/Prim最小生成樹

最小生成樹

定義

連通,但不成環

  • 最小

邊的代價和最小

規律

  • 舉例

    以四個點為例,共需三條線即可。

    1. 同類共四種(任意去掉其中一條線)
    2. 同類共四種
    3. 同類共四種(任意去掉其中一條線)
    4. 同類共四種(任意去掉其中一條線)
  • 總結

    n個點生成樹需要(n-1)條線來連通。

克魯斯卡爾 Kruskal

貪心思想+並查集(檢查是否成環)

  1. 用邊權按從小到大排序
  2. 初始化並查集
  3. 迴圈加邊,檢查是否成環 (n-1條

普萊姆 Prim

運用了,貪心思想

貪心:

一種結果很準確,但是佔的空間很大很大。
所以我們這次要用這種很好的方法來做。

Prim

Prim演算法跟Dij和Bellman-演算法一樣。

也是使用了”藍白點”的思想

Prim演算法每次迴圈都要將一個藍點u變為一個白點,這樣迴圈,min[u]裡面的權還是最小的

  1. 初始化

    對於flag操作的問題:

memset(flag,true,sizeof flag);

解釋:

把flag全部填為真(True)

對於f

for (int i=1;i<=n;++i) f[i]=0x7fffffff; f[1]=0;

注意哦,這裡不能用memset,那樣會卡爆!!

解釋:

如果呢?到了
對於map

memset(map,0,sizeof map);

2.迴圈

for (int i=1;i<=n-1;++i){

    //1.在f中查詢最小權值的編號(且flag==false) 
    int min1=0x7fffffff; 
    int v=-1;

    for (int j=1;j<=n;++j){

        if (flag[j] && min1>f[j]){

            min1=f[j];

            v=j;


        }

    }

    //2.標記v 
    flag[v]=false;

    //3.更新v發出的邊 
    for (int j=1;j<=n;++j){

        if (flag[j] && map[v][j]!=0){

            if (map[v][j]<f[j]) f[j]=map[v][j];

        }

    }

} 

附上完整程式

//鄰接矩陣 


#include <cstdio>
#include <cstring>

const int N=110;

int map[N][N],n,m,x,y,z,f[N];

bool flag[N];

int main(){

    freopen("prim.in","r",stdin);
    freopen("prim.out","w",stdout);

    scanf("%d%d",&n,&m);

    memset(map,0,sizeof map);

    for (int i=1;i<=m;++i){

        scanf("%d%d%d",&x,&y,&z);

        map[x][y]=z; map[y][x]=z;

    }

    memset(flag,true,sizeof flag); 

    for (int i=1;i<=n;++i) f[i]=0x7fffffff; f[1]=0; 

    for (int i=1;i<=n-1;++i){

        //1.在f中查詢最小權值的編號(且flag==false) 
        int min1=0x7fffffff; 
        int v=-1;

        for (int j=1;j<=n;++j){

            if (flag[j] && min1>f[j]){

                min1=f[j];

                v=j;


            }
        //更新我的指令
        //

        }

        //2.標記v 
        flag[v]=false;

        //3.更新v發出的邊 
        for (int j=1;j<=n;++j){

            if (flag[j] && map[v][j]!=0){

                if (map[v][j]<f[j]) f[j]=map[v][j];

            }

        }

    } 

    int ans=0;

    for (int i=1;i<=n;++i) ans+=f[i];

    printf("%d",ans);

    return 0;

}