对于一个边上具有权值的图来说,其边权值和最小的生成树叫做图G的最小生成树

求无向图最小生成树主要有prim和kruskal两种算法

1.prim

将点集V分成Va和Vb两部分,Va为已经连入生成树的点,Vb为没有连入的点,按照边的大小逐渐向Va中加点,直到Va中包含所有点,具体步骤,复杂度O(mlogn)

⑴.首先初始化生成树的权值为0,任选一点放入Va,其余点放入Vb

⑵.在Vb中找一点u,在Va中找一点v(其实v一直不变),使得uv间距离最短,并更新u所连边,这也就是为什么v不变的原因

⑶.重复步骤2,直到Vb中没有点为止

#include <queue>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const double INF=0x3f3f3f3f;
using namespace std;
double dis[],G[][];
int n,x[],y[],vis[];
double prim(int v){
int i,j,u;
double sum,tmp;
sum=;
memset(vis,,sizeof(vis));
for(i=;i<=n;i++)
dis[i]=G[v][i];
vis[v]=;
for(i=;i<n;i++){
u=v;
tmp=INF;
for(j=;j<=n;j++)
if(dis[j]<tmp&&vis[j]==){
tmp=dis[j];
u=j;
} //找出与v相连最小的边
sum+=tmp;
vis[u]=;
for(j=;j<=n;j++)
if(!vis[j]){
if(dis[j]>G[u][j])
dis[j]=G[u][j];
} //更新与u相连的边的权值
}
return sum;
}
int main(){
int i,j;
double ans;
scanf("%d",&n);
for(i=;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(i=;i<=n;i++)
for(j=;j<=n;j++)
G[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
ans=prim(); //通过每个点的坐标算出每个点间距离
printf("%.2lf\n",ans);
return ;
}

2.kruskal

基于贪心的思想逐渐加入边并判断是否形成环,复杂度O(mlogm)

⑴.初始化,并将E进行排序

⑵.不断将边加入图中,并判断是否形成环

⑶.判断选择的边是否是n-1,并计算步骤2的权值和

#include <queue>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int V,E;
int par[],ran[],vis[];
void init(int n){
int i;
for(i=;i<=n;i++){
ran[i]=;
par[i]=i;
}
}
int find(int x){
if(par[x]==x)
return x;
return par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y)
return;
if(ran[x]<ran[y])
par[x]=y;
else{
par[y]=x;
if(ran[x]==ran[y])
ran[x]++;
}
}
bool same(int x,int y){
return find(x)==find(y);
} //并查集判断是否有环
struct node{
int u,v,cost;
};
bool cmp(node a,node b){
return a.cost<b.cost;
}
node es[];
int kruskal(){
int i;
int res=;
init(V);
sort(es,es+E,cmp);
for(i=;i<E;i++){
node e=es[i];
if(!same(e.u,e.v)){
unite(e.u,e.v);
res+=e.cost;
}
}
return res;
}
int main(){
int i;
scanf("%d%d",&V,&E);
memset(vis,,sizeof(vis));
for(i=;i<E;i++)
scanf("%d%d%d",&es[i].u,&es[i].v,&es[i].cost);
printf("%d\n",kruskal());
return ;
}

3.次小生成树

基于最小生成树的算法演变出次小生成树,其实基本的思想就是连入一条不在最小生成树上的边,从而形成一个环,去掉在环中并且在最小生成树上最大的边,遍历所有不在最小生成树上的边并进行同样的操作最小值即为次小生成树,简单证明就是连入一条边后去掉一个最大值相当于比原来的值增加的值最小(增加量=添加的边-环上的某一条边(并且这条边在最小生成树上),添加的边的权值一定,因此使环上的边最大),因次去掉最大的边,kruskal的复杂度是O(mlogm),求出环上的最大值复杂度是O(n*n),因此次小生成树的复杂度是O(mlogm+n*n)

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const double INF=0x3f3f3f3f;
using namespace std;
int dis[],path[][],G[][];
int n,m,pre[],vis[],used[][];
int prim(int v){
int i,j,u,sum,tmp;
sum=;
memset(vis,,sizeof(vis));
memset(used,,sizeof(used));
memset(path,,sizeof(path));
for(i=;i<=n;i++){
dis[i]=G[v][i];
pre[i]=;
}
vis[v]=;
for(i=;i<n;i++){
u=v;
tmp=INF;
for(j=;j<=n;j++)
if(dis[j]<tmp&&vis[j]==){
tmp=dis[j];
u=j;
}
sum+=tmp;
vis[u]=;
used[u][pre[u]]=used[pre[u]][u]=;
for(j=;j<=n;j++){
if(vis[j]&&j!=u) //从j到父节点上的边的最大值和最小生成树上的边之间求最大值
path[u][j]=path[j][u]=max(path[j][pre[u]],dis[u]);
if(!vis[j]){ //与dp有些类似
if(dis[j]>G[u][j]){
dis[j]=G[u][j];
pre[j]=u;
}
}
}
}
return sum;
}
int second_prim(int tmp){
int i,j,ans;
ans=INF;
for(i=;i<=n;i++)
for(j=;j<=n;j++){
if(i!=j&&used[i][j]==)
ans=min(ans,tmp+G[i][j]-path[i][j]);
} //遍历每条边求次小生成树
return ans;
}
int main(){
int i,j,x,y,z,ans,tmp;
scanf("%d%d",&n,&m);
memset(G,INF,sizeof(G));
for(i=;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
G[x][y]=G[y][x]=z;
}
tmp=prim(); //先求出最小生成树
ans=second_prim(tmp);
printf("%d\n",ans);
return ;
}

BY  http://blog.csdn.net/stay_accept/article/details/50960185

最小生成树&&次小生成树的更多相关文章

  1. 训练指南 UVALive - 5713(最小生成树 + 次小生成树)

    layout: post title: 训练指南 UVALive - 5713(最小生成树 + 次小生成树) author: "luowentaoaa" catalog: true ...

  2. [ An Ac a Day ^_^ ] [kuangbin带你飞]专题八 生成树 UVA 10600 ACM Contest and Blackout 最小生成树+次小生成树

    题意就是求最小生成树和次小生成树 #include<cstdio> #include<iostream> #include<algorithm> #include& ...

  3. URAL 1416 Confidential (最小生成树+次小生成树)

    Description Zaphod Beeblebrox - President of the Imperial Galactic Government. And by chance he is a ...

  4. POJ 1679 The Unique MST 【最小生成树/次小生成树模板】

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22668   Accepted: 8038 D ...

  5. 最小生成树(次小生成树)(最小生成树不唯一) 模板:Kruskal算法和 Prim算法

    Kruskal模板:按照边权排序,开始从最小边生成树 #include<algorithm> #include<stdio.h> #include<string.h> ...

  6. HDU 4081 Qin Shi Huang&#39;s National Road System(最小生成树/次小生成树)

    题目链接:传送门 题意: 有n坐城市,知道每坐城市的坐标和人口.如今要在全部城市之间修路,保证每一个城市都能相连,而且保证A/B 最大.全部路径的花费和最小,A是某条路i两端城市人口的和,B表示除路i ...

  7. (最小生成树 次小生成树)The Unique MST -- POJ -- 1679

    链接: http://poj.org/problem?id=1679 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82831#probl ...

  8. POJ 1679 The Unique MST (次小生成树)

    题目链接:http://poj.org/problem?id=1679 有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树). 先求出最小生成树的大小, ...

  9. URAL 1416 Confidential --最小生成树与次小生成树

    题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1 解法:用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就 ...

随机推荐

  1. 【动态规划】洛谷2019 OI春令营 - 普及组 作业

    [P1464 Function] [题解] 按照题目意思进行递归即可,但是过程中需要用到记忆化搜索. #include<bits/stdc++.h> using namespace std ...

  2. Mac电脑配置相关及软件工具安装推荐

    iTerm2(https://www.iterm2.com/) 终端工具 Alfred(http://xclient.info/s/alfred.html) 快速启动器 WebStorm.VSCode ...

  3. Go学习路径--相关基础

    现在开始接触Go一段时间了,基本路径就是看基础学习材料,开始写项目,有问题找解决问题的方法.这里记录一下学习过程. go相关文章 Golang适合高并发场景的原因分析 go build 不同系统下的可 ...

  4. (三)springmvc之注解的基本使用

    一.@Controller @Controller 标记一个类是Controller 二.RequestMapping  地址映射 2.1 Value的操作. 注解在类上面    (父)       ...

  5. Sublime Text 添加C/C++环境

    轻巧便捷的sublime text 3代码编辑功能非常强大,不过作为一款代码编辑软件,我们要是让它能把我们的c或者c++代码run起来,变成一个轻量级编译器那就更好了!今天来给大家说一下怎么在subl ...

  6. Python中的内存管理机制

    Python是如何进行内存管理的 python引用了一个内存池(memory pool)机制,即pymalloc机制,用于管理对小块内存的申请和释放 1.介绍 python和其他高级语言一样,会进行自 ...

  7. js监听audio播放完毕

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. Java 面向对象(一)面向对象思想

    一.面向对象思想 1.概述 Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计.开发计算机程序. 这里的对象泛指现实中一切事 ...

  9. C++ STL 之 常用算法

    #include <iostream> #include <vector> #include <algorithm> using namespace std; // ...

  10. 初识cv

    验证码识别的一般套路: 灰度化.图像处理.二值化.选算法.训练.评估调整参数.预测,当然,我在这里二值化与处理的顺序换了一下,灵活处理哈 1 显示图片轮廓 img = cv2.Canny(img,25 ...