您的位置:首页 > 其它

最小生成树——prim算法

2013-04-19 22:15 441 查看
所谓生成树,就是n个点之间连成n-1条边的图形。而最小生成树,就是权值(两点间直线的值)之和的最小值。
http://sjjp.tjuci.edu.cn/sjjg/DataStructure/DS/web/flashhtml/prim.htm(prim构成最小生成树的演示过程)。
其实原理很简单就是两个集合:一个是图向量的集合,一个是要求的最小生成树的集合,然后就是选择它邻近的最小权值对应的顶点,把顶点和边放入到要求的集合,直到所有元素都放入为止。

Prim算法与Dijkstra算法的区别

在图论中,Prim算法是计算最小生成树的算法,而Dijkstra算法是计算最短路径的算法。二者看起来比较类似,因为假设全部顶点的集合是V,已经被挑选出来的点的集合是U,那么二者都是从集合V-U中不断的挑选权值最低的点加入U,那么二者是否等价呢?也就是说是否Dijkstra也可以计算出最小生成树而Prim也可以计算出从第一个顶点v0到其他点的最短路径呢?答案是否定的,否则就不必有两个算法了。

二者的不同之处在于“权值最低”的定义不同,Prim的“权值最低”是相对于U中的任意一点而言的,也就是把U中的点看成一个整体,每次寻找V-U中跟U的距离最小(也就是跟U中任意一点的距离最小)的一点加入U;而Dijkstra的“权值最低”是相对于v0而言的,也就是每次寻找V-U中跟v0的距离最小的一点加入U。

一个可以说明二者不等价的例子是有四个顶点(v0, v1, v2, v3)和四条边且边值定义为(v0, v1)=20, (v0, v2)=10, (v1, v3)=2, (v3, v2)=15的图,用Prim算法得到的最小生成树中v0跟v1是不直接相连的,也就是在最小生成树中v0v1的距离是v0->v2->v3->v1的距离是27,而用Dijkstra算法得到的v0v1的距离是20,也就是二者直接连线的长度。

相关的应用问题:http://poj.org/problem?id=1258

程序1:

#include<iostream>

using namespace std;

int map[101][101];

int visited[101];

int main() {

int n;

while(cin>>n) {

memset(visited,0,sizeof(visited));

int i,j,k;

memset(map,0,sizeof(map));

for(i=0;i<n;i++)

for(j=0;j<n;j++)

scanf("%d",&map[i][j]);

visited[0]=1;

int temp=0;

int sum=0;

for(i=1;i<n;i++) {

int min=1000000;

for(j=0;j<n;j++)

if(visited[j])

{

for(k=0;k<n;k++){

if(!visited[k]&&map[j][k]<min)

min=map[j][k],temp=k;

}

}

sum+=min;

visited[temp]=1;

}

cout<<sum<<endl;

}

return 0;

程序2:

#include <stdio.h>
#include <string.h>
#define MaxInt 0x3f3f3f3f

#define N 110

//创建map二维数组储存图表,low数组记录每2个点间最小权值,visited数组标记某点是否已访问

int map

,low
,visited
;

int n;
int prim(){

 int i,j,pos,min,result=0;

 memset(visited,0,sizeof(visited));

//从某点开始,分别标记和记录该点

 visited[1]=1;

 pos=1;

//第一次给low数组赋值

 for(i=1;i<=n;i++)

 {

  if(i!=pos)

   low[i]=map[pos][i];

 }

//再运行n-1次

 for(i=1;i<n;i++)

 {

//找出最小权值并记录位置

  min=MaxInt;

  for(j=1;j<=n;j++)

  {

   if(visited[j]==0&&min>low[j])

   {

    min=low[j];

    pos=j;

   }

  }

//最小权值累加

  result+=min;

//标记该点

  visited[pos]=1;

//更新权值

  for(j=1;j<=n;j++)

   if(visited[j]==0&&low[j]>map[pos][j])

    low[j]=map[pos][j];

 }

 return result;

}
int main()

{

 int i,v,j,ans;

 while(scanf("%d",&n)!=EOF)

 {

//所有权值初始化为最大

  memset(map,MaxInt,sizeof(map));

  for(i=1;i<=n;i++)

   for(j=1;j<=n;j++)

   {

    scanf("%d",&v);

    map[i][j]=map[i][j]=v;

   }

  ans=prim();

  printf("%d\n",ans);

 }

 return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: