图论之最小生成树问题(kruskal)
最近有几位同学催我更新,于是来摸摸鱼,来讲一下最小生成树问题。
所谓最小生成树(MST),就是在一张无向带权图中的一棵经过所有节点,边权和最小的一棵树。在实际生活中,可以运用于城镇之间的修路上。
对于MST问题,通常有两种算法,prim算法以及kruskal算法,其中最常用的算法为kruskal算法,其与并查集结合之后可以以O(ElogE)的时间复杂度解决问题,对于稀疏图而言,是一种非常优秀的算法,但是,对于稠密图而言,更适合使用prim算法。这次就只介绍一下kruskal算法。
kruskal算法本质是一种贪心算法,我们知道,树一定无环,我们先对所有边以边权从小到大进行排序,然后从小到大逐个选边,将端点存入并查集中,若边的两个端点发现在同一个并查集中,则会成环,就跳过这个边,否则就把这条边存入MST中。这样我们就得到了一棵最小生成树。易证这种算法的正确性。至于并查集的介绍可以参见我之前的博客。
例题1 hdu1233
还是畅通工程
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 83393 Accepted Submission(s): 37809
当N为0时,输入结束,该用例不被处理。
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int maxn=(1e5)+5;
const int maxm=(1e5)+5;
vector<int>g[maxn];
int par[maxn];
int depth[maxn];
int n,m;
//并查集
void init(int n){
for(int i=0;i<=n;i++){
par[i]=i;
depth[i]=0;
}
}
int find(int x){
if(par[x]==x)return x;
else return par[x]=find(par[x]);
}
void unit(int x,int y){
x=find(x);
y=find(y);
if(x==y)return;
if(depth[x]<depth[y])par[x]=y;
else{
par[y]=x;
if(depth[x]==depth[y])depth[x]++;
}
}
bool same(int x,int y){
return find(x)==find(y);
}
//kruskal算法
struct Edge{
int u,v,w;
}edge[maxm];
bool cmp(Edge x,Edge y){
return x.w<y.w;
}
int kruskal(){
int ans=0;
init(n);
sort(edge+1,edge+m+1,cmp);
for(int i=1;i<=m;i++){
int a=find(edge[i].u);
int b=find(edge[i].v);
if(a==b)continue;//成环
unit(a,b);
ans+=edge[i].w;
}
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
while(n){
m=n*(n-1)/2;
for(int i=1;i<=m;i++){
cin>>edge[i].u>>edge[i].v>>edge[i].w;
}
cout<<kruskal()<<endl;
cin>>n;
}
return 0;
}
例题2 poj2421
| Time Limit: 2000MS | Memory Limit: 65536K | |
| Total Submissions: 35679 | Accepted: 16044 |
Description
We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.
Input
Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.
Output
Sample Input
3
0 990 692
990 0 179
692 179 0
1
1 2
Sample Output
179
题目大意:已知有某些边已经建立了,问使这张图联通的代价是多少。
解析:依然是最小生成树问题,只是先预存边到并查集中,再跑kruskal即可。
代码如下
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int maxn=105;
const int maxm=10005;
int par[maxn];
int depth[maxn];
int n,m;
void init(int n){
for(int i=0;i<=n;i++){
par[i]=i;
depth[i]=0;
}
}
int find(int x){
if(par[x]==x)return x;
else return par[x]=find(par[x]);
}
void unit(int x,int y){
x=find(x);
y=find(y);
if(x==y)return;
if(depth[x]<depth[y])par[x]=y;
else{
par[y]=x;
if(depth[x]==depth[y])depth[x]++;
}
}
bool same(int x,int y){
return find(x)==find(y);
}
struct Edge{
int u,v,w;
}edge[maxm];
bool cmp(Edge x,Edge y){
return x.w<y.w;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int x;
cin>>x;
edge[++cnt].u=i;
edge[cnt].v=j;
edge[cnt].w=x;
}
}
m=cnt;
init(n);
int q;
cin>>q;
while(q--){
int x,y;
cin>>x>>y;
if(!same(x,y))unit(x,y);
}
sort(edge+1,edge+m+1,cmp);
int ans=0;
for(int i=1;i<=m;i++){
int a=find(edge[i].u);
int b=find(edge[i].v);
if(a==b)continue;
unit(a,b);
ans+=edge[i].w;
}
cout<<ans<<endl;
return 0;
}
例题3:poj2377
| Time Limit: 1000MS | Memory Limit: 65536K | |
| Total Submissions: 21954 | Accepted: 8892 |
Description
Realizing Farmer John will not pay her, Bessie decides to do the worst job possible. She must decide on a set of connections to install so that (i) the total cost of these connections is as large as possible, (ii) all the barns are connected together (so that it is possible to reach any barn from any other barn via a path of installed connections), and (iii) so that there are no cycles among the connections (which Farmer John would easily be able to detect). Conditions (ii) and (iii) ensure that the final set of connections will look like a "tree".
Input
* Lines 2..M+1: Each line contains three space-separated integers A, B, and C that describe a connection route between barns A and B of cost C.
Output
Sample Input
5 8
1 2 3
1 3 7
2 3 10
2 4 4
2 5 8
3 4 6
3 5 2
4 5 17
Sample Output
42
Hint
The most expensive tree has cost 17 + 8 + 10 + 7 = 42. It uses the following connections: 4 to 5, 2 to 5, 2 to 3, and 1 to 3.
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int maxn=(1e3)+5;
const int maxm=(2e4)+5;
vector<int>g[maxn];
int n,m;
int par[maxn];
int depth[maxn];
void init(int n){
for(int i=0;i<=n;i++){
par[i]=i;
depth[i]=0;
}
}
int find(int x){
if(par[x]==x)return x;
else return par[x]=find(par[x]);
}
void unit(int x,int y){
x=find(x);
y=find(y);
if(x==y)return;
if(depth[x]<depth[y])par[x]=y;
else{
par[y]=x;
if(depth[x]==depth[y])depth[x]++;
}
}
bool same(int x,int y){
return find(x)==find(y);
}
struct Edge{
int u,v,w;
}edge[maxm];
bool cmp(Edge x,Edge y){
return x.w>y.w;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>edge[i].u>>edge[i].v>>edge[i].w;
}
sort(edge+1,edge+m+1,cmp);
init(n);
ll ans=0;
for(int i=1;i<=m;i++){
int a=find(edge[i].u);
int b=find(edge[i].v);
if(a==b)continue;
unit(a,b);
ans+=edge[i].w;
}
int x=find(1);
for(int i=1;i<=n;i++){
if(find(i)!=x){
ans=-1;
break;
}
}
cout<<ans<<endl;
return 0;
}
总结:kruskal代码看似较长,实际上思路就是简单的贪心以及与并查集的结合,多数可以用模板直接套,修改以下细节即可。
摸结束,谢谢阅读。
图论之最小生成树问题(kruskal)的更多相关文章
- 最小生成树问题---Prim算法与Kruskal算法实现(MATLAB语言实现)
2015-12-17晚,复习,甚是无聊,阅<复杂网络算法与应用>一书,得知最小生成树问题(Minimum spanning tree)问题.记之. 何为树:连通且不含圈的图称为树. 图T= ...
- 【算法】Kruskal算法(解决最小生成树问题) 含代码实现
Kruskal算法和Prim算法一样,都是求最小生成树问题的流行算法. 算法思想: Kruskal算法按照边的权值的顺序从小到大查看一遍,如果不产生圈或者重边,就把当前这条边加入到生成树中. 算法的正 ...
- 最小生成树问题------------Prim算法(TjuOj_1924_Jungle Roads)
遇到一道题,简单说就是找一个图的最小生成树,大概有两种常用的算法:Prim算法和Kruskal算法.这里先介绍Prim.随后贴出1924的算法实现代码. Prim算法 1.概览 普里姆算法(Prim算 ...
- Python小白的数学建模课-18.最小生成树问题
最小生成树(MST)是图论中的基本问题,具有广泛的实际应用,在数学建模中也经常出现. 路线设计.道路规划.官网布局.公交路线.网络设计,都可以转化为最小生成树问题,如要求总线路长度最短.材料最少.成本 ...
- 图论算法-最小费用最大流模板【EK;Dinic】
图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...
- 最小生成树问题:Kruskal算法 AND Prim算法
Kruskal算法: void Kruskal ( ) { MST = { } ; //边的集合,最初为空集 while( Edge ...
- 最小生成树问题(Kruskal 算法)(克鲁斯卡尔)
如图就是Kuskal算法 将图中的每条边按照权值从小到大排序,每次加起来就行,注意的是不要形成回路: 重点是如何用代码实现不能形成回路 看代码; #include <cstdio> #in ...
- 最小生成树问题:kruskal算法
struct edge(int u,v,cost;};bool comp(const edge& e1,const edge& e2){ return e1.cost<e2 ...
- 图论之最小生成树之Kruskal算法
Kruskal算法,又称作为加边法,是配合并查集实现的. 图示: 如图,这是一个带权值无向图我们要求它的最小生成树. 首先,我们发现在1的所有边上,连到3的边的边权值最小,所以加上这条边. 然后在3上 ...
- 最小生成树问题---Prim算法学习
一个具有n个节点的连通图的生成树是原图的最小连通子集,它包含了n个节点和n-1条边.若砍去任一条边,则生成树变为非连通图:若增加一条边,则在图中形成一条回路.本文所写的是一个带权的无向连通图中寻求各边 ...
随机推荐
- 生成19位long型唯一数字id
/** * 生成19位long型唯一数字id * @return */ public static long GetLong19UUID() { // String nanoRandom = Syst ...
- SpringBoot(十五)单个以及多个跨域的配置方法
同源策略是浏览器的一个安全限制,要求域名.协议.端口相同,如果不同则没办法进行数据交互.而跨域配置,则是为了解除这方面的限制.前后端分离的情况下,因为需要分开部署,后台开发基本都需要进行跨域配置了.( ...
- 生态学建模:增强回归树(BRT)预测短鳍鳗生存分布和影响因素|附代码数据
全文下载链接: http://tecdat.cn/?p=22482 最近我们被客户要求撰写关于增强回归树(BRT)的研究报告,包括一些图形和统计输出. 在本文中,在R中拟合BRT(提升回归树)模型.我 ...
- 用户警告:“importlib-metadata”版本与“setuptools”不兼容。升级importlib-metadata
Warning: `importlib-metadata` version is incompatible with `setuptools` 解决方案:升级 importlib-metadata 版 ...
- csr_matrix与ndarray类型互转
ndarry 转 csr_matrix>>> import numpy as np>>> import scipy.sparse >>> my_m ...
- ubuntu iptables 做为路由转发
实现功能,本地服务器的号段的192.168.8.0/24,而做为路由器的机器有2个ip,192.168.8.x和另一个ip,而另一个ip可以访问 192.168.2.0/24号段, 为了让其它192. ...
- response status is 500 https://localhost:7129/swagger/v1/swagger.json
SwaggerGeneratorException: Conflicting method/path combination "GET Test" for actions - To ...
- MFC程序运行原理初探
几年前,写过一段时间的MFC,但是只知其然不知其所以然,最近闲来无事,研究了一下MFC程序的运行顺序,特此记录一下. 首先,如果我们创建一个MFC程序的话,首先会自动生成一个CWinApp的子类,程序 ...
- 嵌入式Qt中实现串口读取的事件驱动方法
在嵌入式Linux系统的UI设计中,比较常见的是使用Qt库来实现.而在Qt中进行程序设计时,也经常会用到串口(UART)通信.现在基于Qt5.1以上的版本中,集成有串口模块(如QSerialPort) ...
- vulnhub:My_Tomcat_Host靶机
kali:192.168.111.111 靶机:192.168.111.171 信息收集 端口扫描 nmap -A -v -sV -T5 -p- --script=http-enum 192.168. ...