图论;最小生成树;普利姆算法;贪心策略;可用最小堆实现;
2010-04-03 22:48
525 查看
#include <iostream> using namespace std; #define MAX 1000 //用于表示顶点之间没有联系 //无向图的邻接矩阵定义 typedef struct { char *vertics;//存放图中结点 int **edge;//存放邻接矩阵 int num;//存放图中顶点数量 }Graph; typedef struct { char vertics;//顶点信息 int weight;//权值 }MinSpanTree;//记录最小生成树的n个结点的信息 //这里用了简单的lowCost[]数组记录当前可选顶点到生成树上的最小距离,更好的办法是利用最小堆 //不断的取当前与生成树具有最小距离的顶点加入到生成树中,更新堆中的每个顶点对应的距离,从而免去了每次都用O(n)时间 //从lowcost[]中取最小距离顶点的时间和判断顶点是否已经加入生成树的if语句 class Prim { private: Graph graph;//定义图 MinSpanTree *tree;//记录最小生成树的信息 public: //构造函数 Prim(int num) { tree=new MinSpanTree[num+1]; graph.vertics=new char[num+1]; graph.edge=new int* [num+1]; for(int i=0;i<=num;i++) { graph.edge[i]=new int[num+1]; } graph.num=num; } //普里姆算法 void prim() { int min;//用于记录最小lowCost int minPoint;//用于记录最小lowCost的顶点编号 int *lowCost=new int[graph.num+1];//num个顶点到生成树上的最小花费,MAX表示与生成树无联系或者已经加入到生成树中 //初始化第一个顶点 lowCost[1]=-1;//花费设置为-1,表示已加入生成树 tree[1].vertics=graph.vertics[1]; tree[1].weight=0; //初始化其他顶点到生成树的花费 for(int i=2;i<=graph.num;i++) { lowCost[i]=graph.edge[1][i]; } //一共加入num-1个顶点(加上第一个顶点则为num个)构成最小生成树 int count=2; while(count<=graph.num) { min=MAX; //找出距离生成树距离最小的且没有加入生成树的点 for(int i=2;i<=graph.num;i++) { if(lowCost[i]!=-1&&lowCost[i]<min) { min=lowCost[i]; minPoint=i; } } //如果不存在点与生成树有联系 if(min==MAX) { cout<<"无法生成最小生成树"<<endl; return; } //记录第count个加入生成树的顶点的信息 tree[count].vertics=graph.vertics[minPoint]; tree[count].weight=lowCost[minPoint]; //设置该顶点的lowCost为MAX,表示已加入生成树 lowCost[minPoint]=-1; //更新lowCost[] for(int i=2;i<=graph.num;i++) { if(lowCost[i]!=-1&&graph.edge[minPoint][i]<lowCost[i]) { lowCost[i]=graph.edge[minPoint][i]; } } ++count; } } //输入图的信息 void input() { int temp; cout<<"下面输入顶点的信息"<<endl; for(int i=1;i<=graph.num;i++) { cout<<"输入第"<<i<<"个顶点:"; cin>>graph.vertics[i]; } for(int i=1;i<=graph.num;i++) { for(int j=i+1;j<=graph.num;j++) { cout<<"输入"<<graph.vertics[i]<<"到"<<graph.vertics[j]<<"的距离"<<endl; cin>>temp; graph.edge[i][j]=temp; graph.edge[j][i]=temp; } } } //输出最小生成树的信息 void display() { for(int i=1;i<=graph.num;i++) { cout<<"第"<<i<<"个加入的顶点为:"<<tree[i].vertics<<",其花费权值:"<<tree[i].weight<<endl; } } }; void main() { Prim test(7);//图有7个顶点 test.input();//输入图的信息 test.prim();//普里姆算法求最小生成树 test.display();//打印生成树的信息 } //测试用图的邻接矩阵如下: // a b c d e // a 50 60 1000 1000 // b 1000 65 40 // c 52 1000 // d 50 // e
这里用了简单的lowCost[]数组记录当前可选顶点到生成树上的最小距离,更好的办法是利用最小堆
不断的取当前与生成树具有最小距离的顶点加入到生成树中,更新堆中的每个顶点对应的距离,从而免去了每次都用O(n)时间
从lowcost[]中取最小距离顶点的时间和判断顶点是否已经加入生成树的if语句
与克鲁斯卡尔算法的共同点与区别:
1.都运用了贪心策略, 普里姆每次取与生成树部分距离最小的顶点加入到生成树中,并做加入记录(lowCost=-1),更新其他顶点到生成树的距离.
克鲁斯卡尔算法则每次选择一个权值最小的边,判断边的两个顶点是否位于同一个连通分量内,如果在同一分量内,那么会成环,不满足最小生成树,所以这条边被抛弃(我的代码里简单的设边权为MAX来做记录,最好另外设置一个标记数组,这样程序可以重复使用)。
如果位于不同连通分量,那么这条边应该加入生成树内,并且把两个顶点所属的连通分量所属集合set进行重新赋值,使他们属于同一个连通分量。 可以容易的相出,如果两个顶点属于不同的连通分量,则他们的set值一定不同,如果属于同一连通分量,则一定相同。 这样的算法思路,成功n-1次时,则形成了n-1条边,最小生成树则形成。
2.区别在于一个以一个顶点为源点开始,贪心选择顶点加入到生成树中,共n次 。 一个不断选择最小边加入到生成树中,加入n-1次。
相关文章推荐
- 贪心策略之最小生成树中的kruskal 算法
- java实现图的最小生成树(MST)的普利姆(Prim)算法
- 最小生成树(普利姆算法、克鲁斯卡尔算法)
- 最小生成树(普利姆算法、克鲁斯卡尔算法)
- C语言实现图的Kruskal最小生成树算法
- 【算法】图论_最小生成树(MST)_Kruskal
- 图论算法之最小生成树
- 基于邻接矩阵存储的无向网图的创建,最小生成树算法实现完整代码
- 最小生成树(普利姆算法、克鲁斯卡尔算法)
- acm pku 1287 Networking的Prim最小生成树算法实现
- 实用算法实现-第 19 第 最小生成树
- [数据结构与算法]最小生成树(普利姆算法、克鲁斯卡尔算法)
- 遗传算法解决TSP问题实现以及与最小生成树的对比
- 最小生成树算法--并查集实现
- 最小生成树(普利姆算法、克鲁斯卡尔算法)
- TopCoder 算法比赛图论实战1—最小生成树问题
- 算法导论-第23章-最小生成树:Prime算法(基于vector)的C++实现
- 【算法】Kruskal算法(解决最小生成树问题) 含代码实现
- 图论之最小生成树-----克鲁斯卡尔(Kruskal)算法
- 最小生成树(普利姆算法、克鲁斯卡尔算法)