最小生成树的kruskal、prim算法
kruskal算法和prim算法
都说 kruskal是加边法,prim是加点法
这篇解释也不错:这篇
1、kruskal算法
因为是加边法,所以这个方法比较合适稀疏图。要码这个需要先懂并查集。因为我不会画好看的图,所以看不懂的话推荐下面博客的说明。这里是下面。
步骤:
1、把每个点都看成一棵树,那么你就会得到一片森林。。。
2、把每棵树之间的距离从小到大排序,即把边排序
3、从小到大取边,把不在同一棵树的点连通到同一棵树上。。。最后你会得到一棵树,就是最小生成树
我去盗图。。。这里的图






给个模板题吧。。HDU1233
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) struct Edge
{
int u, v, w;
bool operator < (const Edge &a) const
{
return w < a.w;
}
}edge[MAXN];
int n, ans, fa[]; //找父节点并压缩路径,这是并查集的知识
int Get_f(int x)
{
if(fa[x] == x)
return x;
return fa[x] = Get_f(fa[x]);
} void Kruskal()
{
//初始化
for(int i = ;i <= n;++i)
fa[i] = i;
sort(edge, edge + (n - ) * n / );
ans = ; int x, y, cnt = ;
for(int i = ;i < n * (n - ) / ;++i)
{
x = Get_f(edge[i].u), y = Get_f(edge[i].v);
//加边
if(x != y)
{
ans += edge[i].w;
fa[x] = y;
cnt++;
}
//加入所有点了
if(cnt >= n)
break;
}
printf("%d\n", ans);
} int main()
{
while(scanf("%d", &n) != EOF && n)
{
for(int i = ;i < n * (n - ) / ;++i)
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
Kruskal();
}
return ;
}
2、Prim算法
这算法写起来跟最短路的 Dijkstra算法很像。来复习一下 Dijkstra算法,先找出距离源点最短的点(这里是找出离一个点最近的路),然后把这个点与。源点连接(这里是连接这两个点),之后再更新最短路(更新到各个点的最短的边,这里代码有点不同)。。。就没有哈哈哈哈。。。直接上上面那道模板题代码吧。。。。。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) int mp[MAXN][MAXN], dis[MAXN], n, ans;
bool vis[MAXN]; void Prim(int s)
{
Mem0(vis);
int i, j;
for(i = ;i <= n;++i)
dis[i] = mp[s][i];
dis[s] = ;
int v, w;
vis[s] = true;
for(i = ;i < n;++i)
{
w = INF;
for(j = ;j <= n;++j)
{
if(!vis[j] && dis[j] < w)
{
w = dis[j];
v = j;
}
}
vis[v] = true;
ans += w;
for(j = ;j <= n;++j)
if(!vis[j] && dis[j] > mp[v][j])//这里不同
dis[j] = mp[v][j];
}
printf("%d\n", ans);
} int main()
{
int a, b, c;
while(scanf("%d", &n) != EOF && n)
{
MemM(mp);
ans = ;
for(int i = ;i < n * (n - ) / ;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp[a][b] = mp[b][a] = c;
}
Prim();
}
return ;
}
3、 STL与kruskal(理论上 Prim算法应该能用优先队列简化找最短路径的操作,就。。不码这个了)
用map存边,简化排序操作。。。先是模板题练练手,可是跑出来时间慢了十几毫秒
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) int ans, n, fa[MAXN];
int Get_F(int x)
{
if(fa[x] == x)
return x;
return fa[x] = Get_F(fa[x]);
} int main()
{
while(scanf("%d", &n) != EOF && n)
{
ans = ;
multimap<int, pair<int, int> > mp;
for(int i = ;i <= n;++i)
fa[i] = i;
int a, b, c;
for(int i = ;i < n * (n - ) / ;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp.insert(make_pair(c, make_pair(a, b)));
}
multimap<int, pair<int, int> > :: iterator it;
int x, y;
for(it = mp.begin();it != mp.end();++it)
{
x = Get_F((*it).second.first), y = Get_F((*it).second.second);
if(x != y)
{
fa[x] = y;
ans += (*it).first;
}
}
printf("%d\n", ans);
}
return ;
}
再给多一道题 UVALive - 6437,先用Prim写一下,感觉Prim比较容易理解,然后再用 kruskal写个简单版的。
Prim思路:。。。。下面注释吧。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) //点数 n,边数 m ,发电站数量 num, 图 mp, 发电站 power
int ans, n, m, num, vis[MAXN], dis[MAXN], mp[MAXN][MAXN];
int power[MAXN];
int Prim()
{
int i, j, k;
// 各个城镇到各个发电站的最短距离
MemM(dis);
for(i = ;i <= n;++i)
for(j = ;j < num;++j)
dis[i] = min(dis[i], mp[i][power[j]]);
int w, v;
// 还要对 n - num 个点找最短路
for(i = ;i < n - num;++i)
{
w = INF;
for(j = ;j <= n;++j)
if(!vis[j] && dis[j] < w)
{
w = dis[j];
v = j;
}
vis[v] = true;
ans += w;
// 这里可以理解为城镇新建了发电站,就看其他城镇到这个新发电站的距离
for(j = ;j <= n;++j)
if(!vis[j] && dis[j] > mp[v][j])
dis[j] = mp[v][j];
}
return ans;
} int main()
{
int T;
scanf("%d", &T);
for(int cas = ;cas <= T;++cas)
{
MemM(mp);
Mem0(vis);
ans = ;
scanf("%d%d%d", &n, &m, &num);
for(int i = ;i <= n;++i)
mp[i][i] = ;
int a, b, c;
for(int i = ;i < num;++i)
{
scanf("%d", &power[i]);
vis[power[i]] = true;//这里先处理发电站比较方便
}
for(int i = ;i < m;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp[a][b] = mp[b][a] = c;
}
printf("Case #%d: %d\n", cas, Prim());
}
return ;
}
Kruskal。。。这道题把所有发电站都先放到一个集合里,那么最后出来的最小生成树就是答案了。。。。具体点就是把所有发电站的祖先都设为同一个,这样不管连接哪一个发电站都有共同祖先。
慢了30ms左右
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack> using namespace std; typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = ;
const int MOD = 1e9 + ; #define MemI(x) memset(x, -1, sizeof(x))
#define Mem0(x) memset(x, 0, sizeof(x))
#define MemM(x) memset(x, 0x3f, sizeof(x)) int ans, n, m, k, fa[MAXN];
int Get_F(int x)
{
if(fa[x] == x)
return x;
return fa[x] = Get_F(fa[x]);
} int main()
{
int T;
scanf("%d", &T);
for(int cas = ;cas <= T;++cas)
{
multimap<int, pair<int, int> > mp;
multimap<int, pair<int, int> > :: iterator it;
ans = ;
scanf("%d%d%d", &n, &m, &k);
for(int i = ;i <= n;++i)
fa[i] = i;
int a, b, c;
//处理发电站
scanf("%d", &a);
for(int i = ;i < k;++i)
{
scanf("%d", &b);
fa[b] = a;
}
for(int i = ;i < m;++i)
{
scanf("%d%d%d", &a, &b, &c);
mp.insert(make_pair(c, make_pair(a, b)));
}
ans = ;
int x, y;
for(it = mp.begin();it != mp.end();++it)
{
x = Get_F((*it).second.first), y = Get_F((*it).second.second);
if(x != y)
{
ans += (*it).first;
fa[x] = y;
}
}
printf("Case #%d: %d\n", cas, ans);
}
return ;
}
最小生成树的kruskal、prim算法的更多相关文章
- 最小生成树(Kruskal+Prim)--模板
最小生成树-----在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树. 应用场景 1.假设以下情景,有一块木板,板上钉上了一些钉子,这些钉子可以由一些细绳连接起来.假设每个钉子可以通 ...
- 数据结构与算法--最小生成树之Prim算法
数据结构与算法--最小生成树之Prim算法 加权图是一种为每条边关联一个权值或称为成本的图模型.所谓生成树,是某图的一棵含有全部n个顶点的无环连通子图,它有n - 1条边.最小生成树(MST)是加权图 ...
- hiho 1097 最小生成树一·Prim算法 (最小生成树)
题目: 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问 ...
- 数据结构之最小生成树Prim算法
普里姆算法介绍 普里姆(Prim)算法,是用来求加权连通图的最小生成树算法 基本思想:对于图G而言,V是所有顶点的集合:现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最 ...
- POJ-3026(图上的最小生成树+prim算法+gets函数使用)
Borg Maze POJ-3026 一开始看到这题是没有思路的,看了题解才知道和最小生成树有关系. 题目的意思是每次走到一个A或者S就可以分为多个部分继续进行搜索.这里就可以看出是从该点分出去的不同 ...
- MAT之prim算法
prim算法 边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1 ...
- Prim算法(普里姆算法)
描述: 一个连通图的生成树是指一个极小连通子图,它含有图中的全部顶点,但只有足以构成一棵树的 n-1 条边.我们把构造连通网的最小代价生成树成为最小生成树.而Prim算法就是构造最小生成树的一种算法. ...
- 数据结构与算法系列研究七——图、prim算法、dijkstra算法
图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph ...
- 贪心算法-最小生成树Kruskal算法和Prim算法
Kruskal算法: 不断地选择未被选中的边中权重最轻且不会形成环的一条. 简单的理解: 不停地循环,每一次都寻找两个顶点,这两个顶点不在同一个真子集里,且边上的权值最小. 把找到的这两个顶点联合起来 ...
- 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind
最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...
随机推荐
- Entity Framework edmx(mapping文件)
<?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="2.0" ...
- hdu 4768 Flyer (异或操作的应用)
2013年长春网络赛1010题 继巴斯博弈(30分钟)签到后,有一道必过题(一眼即有思路). 思路老早就有(40分钟):倒是直到3小时后才被A掉.期间各种换代码姿态! 共享思路: unlucky st ...
- SVN常见问题及解决方式(一)
1.每天早上上班要update SVN,每天下班要commit SVN.2.查看是谁动了我的代码,右键 tortoise 后查看 log 日志.3.文件被别人删除,在空白处右击,show log,可以 ...
- css总结19:HTML5 Canvas(画布)
1 <canvas> 标签定义图形,比如图表和其他图像. 例1:简单使用: <canvas id="Canva" width="200" h ...
- (转)Asp.Net底层原理(三、Asp.Net请求响应过程)
原文地址:http://www.cnblogs.com/liuhf939/archive/2013/09/16/3324753.html 在之前,我们写了自己的Asp.Net框架,对整个流程有了一个大 ...
- 七月小说网 Python + GraphQL (三)
概述 后台数据库几个基本表基本搭建完毕,看了下Github Develop的V4 Api抛弃了RESTful,采用GraphQL,感觉很有意思,一看文档,竟然有Python的开源实现 Graphene ...
- Markdown使用心得
1. 标题的使用 在使用标题时,如果为了层次清晰,可以在"#"后加上"1. "或者"1.1. "这种序号. 每一级标题的正文结束后,最好加一 ...
- c# 根据文件夹或文件名返回(文件夹或文件)的完整路径
c# 根据文件夹或文件名返回(文件夹或文件)的完整路径 一.方案一:(使用windows API) 二.方案二:(扫描全盘)
- 201621123012 《Java程序设计》第1周学习总结
1. 本章学习总结 学习了java的理论知识和它与C语言的差别,什么是JVM,区分JRE与JDK并学习JAVA环境的安装.熟悉控制台下的常用命令,java函数的编写.熟练使用编写JAVA所需要的工具( ...
- 去掉textarea 右下角图标 resize: none;
如下图默认右下角有小图标: 加个样式: resize: none;就可以了: