Prim算法與Kruskal算法探索

以前以爲自己用的生成最小生成樹的方法是Prim算法,今天自己拜讀了《數據結構與算法分析》之後才知道自己有多愚蠢,原來以前一直用的是KrusKal算法。。。。。。

今天好好說道說道這兩個算法:

KrusKal算法用於稀疏圖,貪心策略,連續的按照最小的權值選擇邊。

Prim算法用於稠密圖,也是貪心策略,每次取離小生成樹最近的點作爲生成樹的心點,併入生成樹內生成新的小生成樹,知道所有節點均被納入生成樹後結束。

 

這兩種方法均可得到點點之間路徑最短的聯通圖。

 

例如這個例子:

 

Prim算法的過程:

KrusKal算法的過程:

 

 

 

下面我編碼來實現Prim算法:

(測試數據均是圖一)

  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #define INF 0x11111110  
  4. int map[2010][2010],Tree[2010];  
  5. int closeset[2010];//節點依附的點(就是與生成樹裏那個點鏈接)  
  6. int lowcost[2010];//節點到生成樹的最短距離   
  7. int sum=0;  
  8. void Prim(int n)  
  9. {  
  10.      int i,j,k;  
  11.      int min;  
  12.      Tree[1]=1;//先把 1放在生成樹裏   
  13.      for(i=1;i<=n;i++)  
  14.      {    
  15.          lowcost[i]=map[i][1];//所有節點與生成樹的最短距離初始化   
  16.          closeset[i]=1;//i依附於誰 (初始化都依附於1)   
  17.      }  
  18.      for(j=1;j<=n-1;j++)//n個節點有n-1條邊  
  19.      {  
  20.          min=INF;  
  21.          //找到離生成樹最近的點   
  22.          for(i=1;i<=n;i++)  
  23.          {  
  24.             if(!Tree[i]&&lowcost[i]<min)  
  25.             {  
  26.                min=lowcost[i];  
  27.                k=i;  
  28.             }   
  29.          }  
  30.          printf(”鏈接%d %d 距離爲%d\n”,k,closeset[k],min);   
  31.          sum+=min;  
  32.          Tree[k]=1; //把 k併入生成樹   
  33.          //找到離新加入的點最近的點,更新那個點距生成樹的距離   
  34.          for(i=1;i<=n;i++)  
  35.          {  
  36.             if(!Tree[i]&&map[k][i]<lowcost[i])    
  37.             {  
  38.                lowcost[i]=map[k][i];//更新最小值  
  39.                closeset[i]=k;//記錄新的依附點   
  40.             }   
  41.          }   
  42.      }   
  43.        
  44. }  
  45. int main()  
  46. {  
  47.     int i,j,n,m,x,y,z;  
  48.     while(scanf(“%d %d”,&n,&m)!=EOF)  
  49.     {  
  50.        memset(Tree,0,sizeof(Tree));//用來記錄節點是否在生成樹中   
  51.        memset(map,INF,sizeof(map));  
  52.        for(i=0;i<m;i++)  
  53.        {  
  54.           scanf(”%d %d %d”,&x,&y,&z);  
  55.           map[x][y]=z;  
  56.           map[y][x]=z;  
  57.        }  
  58.        printf(”生成樹的合成順序:\n”);   
  59.        Prim(n);  
  60.        printf(”生成樹的最短距離:%d\n”,sum);   
  61.     }  
  62.     return 0;  
  63. }  
#include<stdio.h>




#include<string.h> #define INF 0x11111110 int map[2010][2010],Tree[2010]; int closeset[2010];//節點依附的點(就是與生成樹裏那個點鏈接) int lowcost[2010];//節點到生成樹的最短距離 int sum=0; void Prim(int n) { int i,j,k; int min; Tree[1]=1;//先把 1放在生成樹裏 for(i=1;i<=n;i++) { lowcost[i]=map[i][1];//所有節點與生成樹的最短距離初始化 closeset[i]=1;//i依附於誰 (初始化都依附於1) } for(j=1;j<=n-1;j++)//n個節點有n-1條邊 { min=INF; //找到離生成樹最近的點 for(i=1;i<=n;i++) { if(!Tree[i]&&lowcost[i]<min) { min=lowcost[i]; k=i; } } printf("鏈接%d %d 距離爲%d\n",k,closeset[k],min); sum+=min; Tree[k]=1; //把 k併入生成樹 //找到離新加入的點最近的點,更新那個點距生成樹的距離 for(i=1;i<=n;i++) { if(!Tree[i]&&map[k][i]<lowcost[i]) { lowcost[i]=map[k][i];//更新最小值 closeset[i]=k;//記錄新的依附點 } } } } int main() { int i,j,n,m,x,y,z; while(scanf("%d %d",&n,&m)!=EOF) { memset(Tree,0,sizeof(Tree));//用來記錄節點是否在生成樹中 memset(map,INF,sizeof(map)); for(i=0;i<m;i++) { scanf("%d %d %d",&x,&y,&z); map[x][y]=z; map[y][x]=z; } printf("生成樹的合成順序:\n"); Prim(n); printf("生成樹的最短距離:%d\n",sum); } return 0; }

 

輸入:

7 12

1 4 1

1 2 2

1 3 4

2 4 3

2 5 10

3 4 2

3 5 6

6 4 8

6 7 1

5 4 7

5 7 6

7 4 4

輸出:

生成樹的合成順序:

鏈接4 1 距離爲1

鏈接2 1 距離爲2

鏈接3 4 距離爲2

鏈接7 4 距離爲4

鏈接6 7 距離爲1

鏈接5 3 距離爲6

生成樹的最短距離:16

 

 

下面我編碼來實現KrusKal算法:

  1. #include<iostream>  
  2. #include<algorithm>  
  3. using namespace std;  
  4. struct node  
  5. {  
  6.    int a,b;  
  7.    int len;  
  8. }per[5000];  
  9. int cmp(node x,node y)  
  10. {  
  11.     if(x.len!=y.len) return x.len<y.len;  
  12. }  
  13. int main()  
  14. {  
  15.     int i,sum,n,m,num;  
  16.     int flag[200];  
  17.     while(scanf(“%d %d”,&n,&m),n!=0)  
  18.     {  
  19.        for(i=0;i<m;i++)  
  20.        {  
  21.           scanf(”%d%d%d”,&per[i].a,&per[i].b,&per[i].len);  
  22.        }  
  23.        sort(per,per+m,cmp);  
  24.        for(i=1;i<=n;i++) flag[i]=1;  
  25.        flag[per[0].a]=0;  
  26.        sum=0;  
  27.        for(i=0;i<m;i++)  
  28.        {  
  29.           num=flag[per[i].a]+flag[per[i].b];  
  30.           if(num==1)  
  31.           {  
  32.              printf(”鏈接%d %d 長度%d\n”,per[i].a,per[i].b,per[i].len);  
  33.              sum+=per[i].len;  
  34.              flag[per[i].a]=flag[per[i].b]=0;  
  35.              i=0;  
  36.           }  
  37.        }  
  38.        printf(”生成樹路徑總和%d\n”,sum);  
  39.     }  
  40.     return 0;  
  41. }  
#include<iostream>




#include<algorithm> using namespace std; struct node { int a,b; int len; }per[5000]; int cmp(node x,node y) { if(x.len!=y.len) return x.len<y.len; } int main() { int i,sum,n,m,num; int flag[200]; while(scanf("%d %d",&n,&m),n!=0) { for(i=0;i<m;i++) { scanf("%d%d%d",&per[i].a,&per[i].b,&per[i].len); } sort(per,per+m,cmp); for(i=1;i<=n;i++) flag[i]=1; flag[per[0].a]=0; sum=0; for(i=0;i<m;i++) { num=flag[per[i].a]+flag[per[i].b]; if(num==1) { printf("鏈接%d %d 長度%d\n",per[i].a,per[i].b,per[i].len); sum+=per[i].len; flag[per[i].a]=flag[per[i].b]=0; i=0; } } printf("生成樹路徑總和%d\n",sum); } return 0; }

 

 輸入

7 12

1 4 1

1 2 2

1 3 4

2 4 3

2 5 10

3 4 2

3 5 6

6 4 8

6 7 1

5 4 7

5 7 6

7 4 4

輸出:

鏈接6 7 長度1

鏈接7 4 長度4

鏈接1 4 長度1

鏈接3 4 長度2

鏈接1 2 長度2

鏈接5 7 長度6

生成樹路徑總和16

 

 

區別一目瞭然……..

 

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