最小生成树——prim算法
2013-04-19 22:15
441 查看
所谓生成树,就是n个点之间连成n-1条边的图形。而最小生成树,就是权值(两点间直线的值)之和的最小值。
http://sjjp.tjuci.edu.cn/sjjg/DataStructure/DS/web/flashhtml/prim.htm(prim构成最小生成树的演示过程)。
其实原理很简单就是两个集合:一个是图向量的集合,一个是要求的最小生成树的集合,然后就是选择它邻近的最小权值对应的顶点,把顶点和边放入到要求的集合,直到所有元素都放入为止。
二者的不同之处在于“权值最低”的定义不同,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;
}
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;
}
相关文章推荐
- 最小生成树-Prim算法和Kruskal算法
- ACM日记——最小生成树.prim算法
- 最小生成树之Prim算法
- zoj1586 QS Network ——最小生成树入门题_Prim算法
- poj2349 Arctic Network ——最小生成树入门题_Prim算法
- POJ-2031 Building a Space Station(最小生成树 prim算法)
- poj1789 Truck History(最小生成树Prim算法)
- Prim算法(最小生成树) 我TM只能先做到这儿了 后面继续补充
- poj3026Borg Maze_最小生成树(广搜+prim算法)
- POJ 1789 求车类型字符串距离最小值 最小生成树 prim算法
- 最小生成树 ———prim算法 poj 1258
- 最小生成树之PRIM算法
- 最小生成树——prim算法(个人总结)
- 贪婪算法在求解最小生成树中的应用(JAVA)--Prim算法
- 最小生成树——Prim算法
- hdu 还是畅通工程 (基础)(最小生成树)(Prim算法 && Kruskal算法)
- hdu 畅通工程再续(最小生成树)(Prim算法 && Kruskal算法)
- 最小生成树-Prim算法
- 图的最小生成树:Prim算法实现
- 最小生成树--prim算法