贪心算法之最小生成树Kruskal
2012-11-07 16:48
357 查看
求最小生成树有两种算法prim和kruskal。 前者适合于稠密图,它是根据节点到周围节点的最短路径来求的的。前面已经介绍过,本人也认为它编程思想比较简单适合于初学者。而kruskal根据边数来求的的,它始终取当前最小边加入,所以它适合于稀疏图,当边数非常多时,它就会很复杂。
很多数据结构书上都讲过这种贪心思想,这种思想还好理解,但是要将它具体写成程序还是有一些难度的,我想按照prim算法的思想,将最小边的节点放在visited[]数组中,如果最小边的节点访问过,则visited[i] = 1;否则为0.但是这种想法不行,比如下面第四幅图 ,1 ,3连接,2,6连接起来后,然后进行贪心的话,就会出现错误。
先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n
棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
很多数据结构书上都讲过这种贪心思想,这种思想还好理解,但是要将它具体写成程序还是有一些难度的,我想按照prim算法的思想,将最小边的节点放在visited[]数组中,如果最小边的节点访问过,则visited[i] = 1;否则为0.但是这种想法不行,比如下面第四幅图 ,1 ,3连接,2,6连接起来后,然后进行贪心的话,就会出现错误。
先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n
棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
#include <iostream> #include <queue> using namespace std; priority_queue<struct Edge> pq; // 并查集 class UFSet { int n; int *root; public: ~UFSet(); UFSet(int n); int Find(int x); void Merge(int x, int y); }; class UFSet *ufset; //函数定义 UFSet::UFSet(int n) { this->n = n; root = new int[n+1]; for (int i = 1; i <= n; i++) root[i] = i; } UFSet::~UFSet() { delete[] root; } int UFSet::Find(int x) { int t, r = root[x]; while (root[r] != r) r = root[r]; //这段其实也很不好理解,但可以结合上图的最后一幅图,假设其中1和4还有一条连线 ,就可以帮助我们理解了 /*hile (root[x] != r) // 路径压缩 //其实这段代码没有功能 ,个人看法。如果有不同的看法可以跟我说 { t = root[x]; root[x] = r; x = t; }*/ return r; } void UFSet::Merge(int x, int y) { //int fx = Find(x); //网上原先还是对形参进行find操作,但我觉得和main函数中的find重复操作,冗余,所以就将其伪码修改了下 //int fy = Find(y); //if (fx != fy) root[x] = y; } // 边 struct Edge { int left; int right; double dis; bool operator < (const Edge& e) const { return dis > e.dis; } }; /* bool com(const Edge& e1,const Edge &e2) { return e1.dis < e2.dis; }*/ // 边集合 double Kruskal() { double ans = 0; while( ! pq.empty() ) { struct Edge e = pq.top(); pq.pop(); int fx = ufset->Find(e.left); int fy = ufset->Find(e.right); if (fx != fy) { ufset->Merge(fx, fy); ans += e.dis; } } return ans; } int main() { cout<<"输入定点个数 :"; int v; cin>>v; UFSet uf(v); ufset = &uf; //ufset->UFSet(v); struct Edge edge[100]; int n; cout<<"输入边的个数:"; cin>>n; for(int i=1; i<=n; i++) { cin>>edge[i].left>>edge[i].right; cin>>edge[i].dis; } for(int i=1; i<=n; i++) pq.push(edge[i]); cout<<Kruskal()<<endl; return 1; }
相关文章推荐
- 贪心算法之最小生成树prim与单源最短路径dijkstra
- 贪心算法之最小生成树(Prim)
- 贪心算法基础之最小生成树prim算法 51nod prim模板
- 贪心策略之最小生成树中的kruskal 算法
- C++——算法基础之最小生成树(Prim 和 Kruskal)
- 贪心算法之最小生成树prim算法
- 贪心生成最小生成树-克鲁斯卡尔(Kruskal)算法(归并排序)(并查集)
- 数据结构之(图之最小生成树)Kruskal(克鲁斯卡尔)算法
- 图结构之最小生成树(MST)——Prims(普里姆)算法、Kruskal(克鲁斯卡尔)算法
- 贪心算法——n个数连接得到最小或最大的多位整数
- 最小生成树算法(prim&kruskal)
- 算法总结之最小生成树
- 贪心算法练习:寻找最小数
- Kruskal最小生成树算法
- 最小生成树算法(Prim和Kruskal)
- poj 1751 Highways 最小生成树之Kruskal(克鲁斯卡尔)算法
- 算法整理:最小生成树(mst)-Prim+Kruskal
- ACM_程序设计竞赛:贪心算法:字典最小序
- C++代码,数据结构-最小生成树的两个算法,Prime&Kruskal
- 计科1111-1114班第六周讲义、课外作业(贪心算法之最小生成树、哈夫曼编码,截止日期:2014年4月18日23点-周五晚,学委飞信通知同学)