最小生成树求法 Prim + Kruskal
prim算法的思路 和dijkstra是一样的
每次选取一个最近的点 然后去向新的节点扩张 注意这里的扩张 不再是 以前求最短路时候的到新的节点的最短距离
而是因为要生成一棵树 所以是要连一根最短的连枝 所以关键部分修改一下
dist[u] = min(dist[u], e.cost) --->>e是连接 v 和 u的边
同样地 普同写法O(v^2) 用队列优化后O(E*logV)
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#define MAXV 256
#define MAXE 256
#define INF 0x3f3f3f3f using namespace std;
typedef pair<int,int> P;
int V, E;
//和dijkstra完全一样
//书上写法 O(V^2)
int graph[MAXV][MAXV];
int prim()
{
int dist[MAXV];
int res = ;
bool use[MAXV];
fill(dist, dist+MAXV, INF);
fill(use, use+MAXV, );
dist[] = ;//假定1为源点
while (true)
{
int v = -;
for (int i = ; i <= V; i++)
{
if (!use[i] && (v == - || dist[i] < dist[v])) v = i;//查找离原点最近的点
}
if (v == -) break;
use[v] = true;
res += dist[v];
cout << dist[v] << endl; //打印树枝的情况
for (int i = ; i <= V; i++)
{
dist[i] = min(dist[i], graph[v][i]);//这里是唯一的区别 --->>.但其实 这个dist中的值 最后是有问题的 这样最后dist保存的 是离它最近的一个节点的边的值
//第33行打印的结果之所以正确是因为 按着离原点最近的顺序 向外扩张 在dist改变之前已经打印了 但是打印之后它的值是可能会发生改变的
/*
3).重复下列操作,直到Vnew = V: a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,
而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一); b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
*/
}
}
return res;
} //使用堆维护 再使用prim O(E*logV)
struct Edge
{
int to, cost, next;
Edge() {}
Edge(int to, int cost, int next) : to(to), cost(cost), next(next) {}
}edge[MAXE];
int num = ;
int head[MAXV];
void Add(int from, int to, int cost)
{
edge[num] = Edge(to, cost, head[from]);
head[from] = num++;
} int prim2()
{
int dist[MAXV], res = ;
bool use[MAXV];
fill(use, use+MAXV, false);
fill(dist, dist+MAXV, INF);
priority_queue<P, vector<P>, greater<P> > que;
dist[] = ;//假定1为源点
que.push(P(dist[], ));//first -->距离 second -->编号
while(!que.empty())
{
P p = que.top();
que.pop();
if (!use[p.second])//这个也是那个问题 先前点(作为现在去扩张的点 如果被打印过 就不再去打印它了 总之算法思路就是 从原点开始 让最近的一个点去扩张)
{
res += dist[p.second];
cout << dist[p.second] << endl;
}
use[p.second] = true;
if (dist[p.second] < p.first)
{
continue;
}
int t = head[p.second];
while (t != -)
{
Edge e = edge[t];
if (!use[e.to] && dist[e.to] > e.cost)
{
dist[e.to] = e.cost;
que.push(P(e.cost, e.to));
}
t = e.next;
}
}
return res;
} int main()
{
freopen("in.txt", "r", stdin);
scanf("%d%d", &V, &E);
memset(edge, -, sizeof(edge));
memset(head, -, sizeof(head));
for(int i = ; i <= V; i++)
for (int j = ; j <= V; j++) graph[i][j] = INF;
for (int i = ; i < E; i++)
{
int from, to, cost;
scanf("%d%d%d", &from, &to, &cost);
graph[from][to] = cost;
graph[to][from] = cost;
Add(from, to, cost);
Add(to, from, cost);
}
int ans = prim2();
cout << ans << endl;
}
Kruskal -->> O(E*logV) 思路就更加的简单
将所有的边 排序
贪心地从小到大取 如果连接进一个新的点 就加入树枝的集合中 最终 得到的边的集合就是最小生成树
这里判断是否是新的节点 就是判断连通性 那么就使用并查集非常容易
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAXV 256
#define MAXE 256
#define INF 0x3f3f3f3f
using namespace std; int E, V;
//Kruskal 思路: 按边的角度出发 将边从小到大排序 如果 from to 不再一个连通块中 就可以取这一条边(不会产生环)
struct Edge
{
int from, to, cost;
Edge(){}
Edge(int from, int to, int cost) : from(from), to(to), cost(cost) {}
}edge[MAXE]; int par[MAXV];
int find(int x)
{
if(x == par[x]) return x;
else return par[x] = find(par[x]);
}
void unite(int x, int y)
{
int px = find(x), py = find(y);
if (px == py) return ;
else par[py] = px;
}
bool same(int x, int y)
{
int px = find(x), py = find(y);
return px == py;
} bool cmp(Edge e1, Edge e2)
{
return e1.cost < e2.cost;
} //O(E*logV) -->>对于并查集的操作是logN
int Kruskal()
{
int res = ;
for (int i = ; i <= V; i++) par[i] = i;
sort(edge, edge+E, cmp);
for (int i = ; i < E; i++)
{
Edge e = edge[i];
if (!same(e.from, e.to))
{
cout << e.from << " " << e.to << " : " << e.cost << endl;
res += e.cost;
unite(e.from, e.to);
}
}
return res;
} int main()
{
freopen("in.txt", "r", stdin);
scanf("%d%d", &V, &E);
for (int i = ; i < E; i++)
{
int from, to, cost;
scanf("%d%d%d", &from, &to, &cost);
edge[i] = Edge(from, to, cost);
}
int ans = Kruskal();
cout << ans << endl;
return ;
}
转一篇写的很详细的博客
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html
最小生成树求法 Prim + Kruskal的更多相关文章
- 最小生成树(prim&kruskal)
最近都是图,为了防止几次记不住,先把自己理解的写下来,有问题继续改.先把算法过程记下来: prime算法: 原始的加权连通图——————D被选作起点,选与之相连的权值 ...
- 最小生成树之Prim Kruskal算法(转)
最小生成树 首先,生成树是建立在无向图中的,对于有向图,则没有生成树的概念,所以接下来讨论的图均默认为无向图.对于一个有n个点的图,最少需要n-1条边使得这n个点联通,由这n-1条边组成的子图则称为原 ...
- 最小生成树算法 prim kruskal两种算法实现 HDU-1863 畅通工程
最小生成树 通俗解释:一个连通图,可将这个连通图删减任意条边,仍然保持连通图的状态并且所有边权值加起来的总和使其达到最小.这就是最小生成树 可以参考下图,便于理解 原来的图: 最小生成树(蓝色线): ...
- 数据结构之 图论---最小生成树(prim + kruskal)
图结构练习——最小生成树 Time Limit: 1000MS Memory limit: 65536K 题目描述 有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的.现在我们想知 ...
- 最小生成树算法(Prim,Kruskal)
边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...
- 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)
最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...
- C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)
1.Prim 算法 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 2.Kruskal 算法 直接寻找最小权值的边来构建最小生成树. 比较: Kruskal 算法主要是针对边来展开,边数 ...
- 最小生成树详解 prim+ kruskal代码模板
最小生成树概念: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边. 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里 ...
- java实现最小生成树的prim算法和kruskal算法
在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...
随机推荐
- AJPFX关于读取properties 配置文件 返回属性值
:Properties的概述 * Properties 类表示了一个持久的属性集. * Properties 可保存在流中或从流中加载. * 属性列表中每个键 ...
- [转]Intellij Idea自动添加注释的方法
Intellij Idea自动添加注释的方法 阿历Ali 关注 2017.08.20 21:22* 字数 914 阅读 2741评论 0喜欢 6 程序媛阿历终于要写第一篇关于开发的文章了!!! 阿历用 ...
- 微信小程序 开放能力学习
1. 用户信息小程序登录使用微信的个人信息快速搭建用户体系,登录逻辑:小程序向微信获取code 给服务端生成用户. 说明1. 小程序端调用 wx.login() 获取临时登录凭证 code,并传到服务 ...
- jsapi4加载的首个图层的范围被默认作为地图范围,且不能修改的解决
在map加载的第一个图层的图层范围(fullExtent),会被默认设置为map的全图范围,且不能更改,从一般地图控件角度来说,应该有fullExtent属性,作为地图的全图范围,但很遗憾jsapi4 ...
- Implicit Animations 默认动画 读书笔记
Implicit Animations 默认动画 读书笔记 Do what I mean, not what I say. Edna Krabappel, The Simpsons Part I ...
- mongoDB学习初步总结
What? 最受欢迎的非关系型数据库之一.面向文档的数据库,在存储乎数据方面与关系型数据库有着本质的区别. Why? 简单易用 对多变的业务需求,适应性强于SQL型DB 性能 复制 索引 分片 丰富的 ...
- Photoshop 注册破解
本机测试环境为Photoshop cs4 破解方式一: 打开C:\windows\system32\drivers\etc\"找到 hosts 文件, 右键点击--打开方式---记事本,然后 ...
- docker 新手入门 (阿里镜像仓库的使用)
创建镜像仓库后的步骤是: https://help.aliyun.com/document_detail/60743.html?spm=a2c4g.11186623.6.546.79be52f3y ...
- Django 路由 —— Djangon如何处理一个请求
Django URL路由概述 一个干净优雅的URL方案是高质量Web应用程序中的一个重要细则Django可以让你设计URL,无论你想要什么,没有框剪限制要为应用程序设计URL,您可以非正式地创建一个名 ...
- 【软件构造】第三章第五节 ADT和OOP中的等价性
第三章第五节 ADT和OOP中的等价性 在很多场景下,需要判定两个对象是否 “相等”,例如:判断某个Collection 中是否包含特定元素. ==和equals()有和区别?如何为自定义 ADT正确 ...