Prim算法与Kruskal算法探索

来源:互联网 发布:c语言leap什么意思 编辑:程序博客网 时间:2024/05/29 19:34

以前以为自己用的生成最小生成树的方法是Prim算法,今天自己拜读了《数据结构与算法分析》之后才知道自己有多愚蠢,原来以前一直用的是KrusKal算法。。。。。。

今天好好说道说道这两个算法:

KrusKal算法用于稀疏图,贪心策略,连续的按照最小的权值选择边。

Prim算法用于稠密图,也是贪心策略,每次取离小生成树最近的点作为生成树的心点,并入生成树内生成新的小生成树,知道所有节点均被纳入生成树后结束。

 

这两种方法均可得到点点之间路径最短的联通图。

 

例如这个例子:

 

Prim算法的过程:

KrusKal算法的过程:

 

 

 

下面我编码来实现Prim算法:

(测试数据均是图一)

[cpp] view plain copy
print?
  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 0x11111110int 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算法:

[cpp] view plain copy
print?
  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

 

 

区别一目了然……..

 

原创粉丝点击