【算法小總結】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