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的更多相关文章

  1. 最小生成树(prim&kruskal)

    最近都是图,为了防止几次记不住,先把自己理解的写下来,有问题继续改.先把算法过程记下来: prime算法:                  原始的加权连通图——————D被选作起点,选与之相连的权值 ...

  2. 最小生成树之Prim Kruskal算法(转)

    最小生成树 首先,生成树是建立在无向图中的,对于有向图,则没有生成树的概念,所以接下来讨论的图均默认为无向图.对于一个有n个点的图,最少需要n-1条边使得这n个点联通,由这n-1条边组成的子图则称为原 ...

  3. 最小生成树算法 prim kruskal两种算法实现 HDU-1863 畅通工程

    最小生成树 通俗解释:一个连通图,可将这个连通图删减任意条边,仍然保持连通图的状态并且所有边权值加起来的总和使其达到最小.这就是最小生成树 可以参考下图,便于理解 原来的图: 最小生成树(蓝色线): ...

  4. 数据结构之 图论---最小生成树(prim + kruskal)

    图结构练习——最小生成树 Time Limit: 1000MS Memory limit: 65536K 题目描述  有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的.现在我们想知 ...

  5. 最小生成树算法(Prim,Kruskal)

    边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...

  6. 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

    最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...

  7. C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)

    1.Prim 算法 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 2.Kruskal 算法 直接寻找最小权值的边来构建最小生成树. 比较: Kruskal 算法主要是针对边来展开,边数 ...

  8. 最小生成树详解 prim+ kruskal代码模板

    最小生成树概念: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边. 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里 ...

  9. java实现最小生成树的prim算法和kruskal算法

    在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...

随机推荐

  1. AJPFX总结之Socket编程

    一.Socket简介 Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换. 几个定义: (1)IP地址:即依照TCP/IP协议分配给本地主机的 ...

  2. laravel如何查找门脸及注入类方法

    门脸模式 通过 config/app.php 查看别名对应类名 Illuminate\Support\Facades\Log ,查看 LoggerInterface 类文件,得:命名空间+接口名 Ps ...

  3. Mac上安装Homebrew和wget

    实际上是使用Homebrew来安装wget 安装Homebrew Homebrew一般称为brew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件, 只需要一个命令, 非常 ...

  4. 应用-如何使不同的企业使用独自的数据源。使用ejb3.0+jboss6.2EAP+JPA

    摘要:                如何使不同的企业使用独自的数据源.使用ejb3.0+jboss6.2EAP+JPA10C应用系统被多个企业同时使用,为了提供个性化服务,如何使不同的企业使用独自的 ...

  5. COGS 74. [NOIP2006] 明明的随机数 (Splay小练习。。)

    ☆   输入文件:random.in   输出文件:random.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述]    明明想在学校中请一些同学一起做一项问卷调查,为了 ...

  6. Android(java)学习笔记167:横竖屏切换时Activity的生命周期

    1.横竖屏切换的生命周期     默认情况下横竖屏切换,先销毁再创建 2.有的时候,默认情况下的横竖屏切换(先销毁再创建),对应用户体验是不好的,比如是手机游戏横竖屏切换对游戏体验非常不好,下面两种方 ...

  7. iptables 防火墙

    运行源地址为192.168.10.10-192.168.10.50 这个网段的机器访问本机的20-25还有80.443.6379端口进来的流量 iptables -A INPUT -p tcp -m ...

  8. python爬虫---从零开始(一)初识爬虫

    我们开始来谈谈python的爬虫. 1,什么是爬虫: 网络爬虫是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用的名字还有蚂蚁.自动索引.模拟程序或者蠕虫.互联网犹如一个大蜘蛛 ...

  9. QT5:第二章 布局排版控件

    一.简介 在QT组件面板中有Layouts和Spacers两个组件面板 注意:布局排版控件不显示 1.Layouts(布局) Vertical Layout:垂直方向布局,组件自动在垂直方向上分布 H ...

  10. 洛谷——P1627 [CQOI2009]中位数

    P1627 [CQOI2009]中位数 给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b.中位数是指把所有元素从小到大排列后,位于中间的数. 中位数的题目有关统计的话,可以转 ...