最小生成树求法 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关于抽象类和接口的区别
一.设计目的不同:接口体现的是一种规范,,类似于系统的总纲,它制定了系统的各模块应遵守的标准抽象类作为多个子类的共同父类,体现的是模式化的设计,抽象类可以认为是系统的中间产品,已经实现了部分功能,部分 ...
- jQuery选择器之属性筛选选择器
在这么多属性选择器中[attr="value"]和[attr*="value"]是最实用的 [attr="value"]能帮我们定位不同类型 ...
- IOS数组
/*******************************************************************************************NSArray ...
- SAP CRM和Cloud for Customer中的Event handler(事件处理器)
SAP CRM可以在开发工具中用右键直接创建一个新的事件处理器: 这些事件处理器实际上就是UI控制器(Controller)上具有特定接口类型的方法. C4C UI的event handler 在C4 ...
- Python 风格规范
分号 不要在行尾加分号, 也不要用分号将两条命令放在同一行. 行长度 每行不超过80 个字符 例外: 如果使用Python 2.4 或更早的版本, 导入模块的行可能多于80 个字符. Pyth ...
- Unity复杂的旋转-欧拉角和四元数
一.欧拉角欧拉角最容易表示,用三个变量X,Y,Z可以直观的表示绕着某个轴的旋转角度. 在Unity里就是Transform组件的Rotation里的X Y Z三个变量代表了欧拉角 二.四元数四元数相比 ...
- Linux之用户权限管理
chmod(更改目录或文件权限) 在linux中,文件的权限分为3中,拥有者,群组,其他人.而chmod则是对权限更改的命令. u 表示该文件的拥有者,g 表示与该文件的拥有者属于同一个组,o 表示其 ...
- uva1611 Crane
类似煎饼,先把1放到1,之后是子问题 (先放到前一半,再放到开头,两次操作)(任何位置,最多一次就可以放到前一半)) #include<iostream> #include<ve ...
- autoHeight.vue 高度自适应
autoHeight.vue 高度自适应 <!-- * @description 自适应高度 * @fileName autoHeight.vue * @author 彭成刚 * @date 2 ...
- 原生查找DOM的方法
JS获取DOM元素的方法(8种) 通过ID获取(getElementById) 通过name属性(getElementsByName) 通过标签名(getElementsByTagName) 通过类名 ...