閱讀805 返回首頁    go 汽車大全


【算法小總結】Prim算法與Kruskal算法探索

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

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

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

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

 

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

 

例如這個例子:

 

Prim算法的過程:

KrusKal算法的過程:

 

 

 

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

(測試數據均是圖一)

#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算法:

#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

 

 

區別一目了然........

 

最後更新:2017-04-03 05:39:37

  上一篇:go Kafka詳解二、如何配置Kafka集群
  下一篇:go 【PHP】基於ThinkPHP框架搭建OAuth2.0服務