prim算法
最小生成树
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
普里姆算法(Prim算法)
图例所示:
1)图中有6个顶点v1-v6,每条边的边权值都在图上;在进行prim算法时,我先随意选择一个顶点作为起始点,当然我们一般选择v1作为起始点,好,现在我们设U集合为当前所找到最小生成树里面的顶点,TE集合为所找到的边,现在状态如下:
U={v1}; TE={};
(2)现在查找一个顶点在U集合中,另一个顶点在V-U集合中的最小权值,如下图,在红线相交的线上找最小值。
通过图中我们可以看到边v1-v3的权值最小为1,那么将v3加入到U集合,(v1,v3)加入到TE,状态如下:
U={v1,v3}; TE={(v1,v3)};
(3)继续寻找,现在状态为U={v1,v3}; TE={(v1,v3)};在与红线相交的边上查找最小值。
我们可以找到最小的权值为(v3,v6)=4,那么我们将v6加入到U集合,并将最小边加入到TE集合,那么加入后状态如下:
U={v1,v3,v6}; TE={(v1,v3),(v3,v6)}; 如此循环一下直到找到所有顶点为止。
(4)下图像我们展示了全部的查找过程:
相关题目:
- 题目描述:
-
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。输入:
-
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
- 输出:
-
对每个测试用例,在1行里输出最小的公路总长度。
- 样例输入:
-
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
- 样例输出:
-
3
5
实现算法(c++):
//Prim Algorithm
#include <iostream>
#include <fstream>
#include <cstring>
#include <queue>
#define CITY 101
#define INFINITE 0x7fffffff
using namespace std;
int dist[CITY][CITY];
int flag[CITY];
int cityNum;
int prim();
int visitedCount();
int main()
{
//ifstream cin("input.txt");
int i;
while(cin>>cityNum)
{
if(cityNum==0)
break;
memset(dist,0,sizeof(dist));
memset(flag,0,sizeof(flag));
int terA,terB,distance;
for(i=0;i<(cityNum*(cityNum-1)/2);i++)
{
cin>>terA>>terB>>distance;
dist[terA][terB]=distance;
dist[terB][terA]=distance;
}
cout<<prim()<<endl;
}
}
int prim()
{
int i,j;
int newBegin,newEnd;
int allDistance=0;
flag[1]=1;
while(visitedCount()<cityNum)
{
int min=INFINITE;
for(i=1;i<=cityNum;i++)
{
if(flag[i]==1)
{
for(j=1;j<=cityNum;j++)
{
if(flag[j]==0)
if(dist[i][j]<min)
{
min=dist[i][j];
newBegin=i;
newEnd=j;
}
}
}
}
flag[newEnd]=1;
allDistance+=dist[newBegin][newEnd];
}
return allDistance;
}
int visitedCount()
{
int i,sum=0;
for(i=1;i<=cityNum;i++)
if(flag[i]==1)
sum++;
return sum;
}
算法解析:
dist是二维数组,第i行第j列存储着第i个城市到第j个城市的距离。dist是一个对称矩阵。
cityNum是城市的数量;
用一个flag数组来存储每个城市是否已经被加入最小生成树中。
对于已经加入最小生成树的节点,其在flag数组中对应的项为1;
当加入树的节点的个数小于citynumber时
循环
将最小值清0;
{
对每个生成树中的城市i
{
在其他城市(未加入生成树)与第i个城市的距离中挑选最小值;
记录最小值
记录最小值对应的起始城市i;
记录最小值对应的终点城市j;
}
将城市j加入生成树;
最短距离+最小值成为新的最短距离;
}
-