最小生成树求法 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算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...
随机推荐
- 【学习笔记】彻底理解JS中的this
首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...
- Smart SVN的使用
最近项目使用了SVN,为管理代码起到了很好的作用!但是,对于很多初步使用着,还是非常不容易! 公司使用的是Smart SVN 客户端. Smart SVN 这个工具总体还是挺不错的! 在代码的提交和获 ...
- spring mvc 解决 Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml] 异常
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document fro ...
- vue跨域解决及打包
打包之前需要修改如下配置文件: 配置文件一:build>>>utils.js (修改publicPath:"../../" , 这样写是处理打包后找不到静态文件( ...
- codevs 5438 zbd之难题(水题日常)
时间限制: 1 s 空间限制: 1000 KB 题目等级 : 白银 Silver 题目描述 Description zbd想要一个计算器,请你编一个计算器. 输入描述 Input Descrip ...
- 深入Docker 存储驱动 (转)
参考: http://static.dockerone.com/ppt/filedriver.html#28
- (译文)IOS block编程指南 3 概念总览
Conceptual Overview(概览) Block objects provide a way for you to create an ad hoc function body as an ...
- core 中使用 nlog
引包 代码 public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory logFac) ...
- HTML基础(一)
什么是HTMLHTML Hypertext Markup Language:即超文本标记语言 HTML特点 1.HTML不需要编译,直接由浏览器执行 2.HTML文件是一个文本文件 3.HTML文件必 ...
- 阿里云首次安装和部署nginx
1.执行yum命令安装依赖 yum -y install pcre* yum -y install openssl* 2.下载nginx //如果没有安装wget,下载已编译版本 yum instal ...