最小生成树&&次小生成树
对于一个边上具有权值的图来说,其边权值和最小的生成树叫做图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
最小生成树&&次小生成树的更多相关文章
- 训练指南 UVALive - 5713(最小生成树 + 次小生成树)
layout: post title: 训练指南 UVALive - 5713(最小生成树 + 次小生成树) author: "luowentaoaa" catalog: true ...
- [ An Ac a Day ^_^ ] [kuangbin带你飞]专题八 生成树 UVA 10600 ACM Contest and Blackout 最小生成树+次小生成树
题意就是求最小生成树和次小生成树 #include<cstdio> #include<iostream> #include<algorithm> #include& ...
- URAL 1416 Confidential (最小生成树+次小生成树)
Description Zaphod Beeblebrox - President of the Imperial Galactic Government. And by chance he is a ...
- POJ 1679 The Unique MST 【最小生成树/次小生成树模板】
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22668 Accepted: 8038 D ...
- 最小生成树(次小生成树)(最小生成树不唯一) 模板:Kruskal算法和 Prim算法
Kruskal模板:按照边权排序,开始从最小边生成树 #include<algorithm> #include<stdio.h> #include<string.h> ...
- HDU 4081 Qin Shi Huang's National Road System(最小生成树/次小生成树)
题目链接:传送门 题意: 有n坐城市,知道每坐城市的坐标和人口.如今要在全部城市之间修路,保证每一个城市都能相连,而且保证A/B 最大.全部路径的花费和最小,A是某条路i两端城市人口的和,B表示除路i ...
- (最小生成树 次小生成树)The Unique MST -- POJ -- 1679
链接: http://poj.org/problem?id=1679 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82831#probl ...
- POJ 1679 The Unique MST (次小生成树)
题目链接:http://poj.org/problem?id=1679 有t组数据,给你n个点,m条边,求是否存在相同权值的最小生成树(次小生成树的权值大小等于最小生成树). 先求出最小生成树的大小, ...
- URAL 1416 Confidential --最小生成树与次小生成树
题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1 解法:用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就 ...
随机推荐
- apache - storm - Setting Up a Development Environment
Installing a Storm release locally If you want to be able to submit topologies to a remote cluster f ...
- Fabric分支/版本切换问题
(以下示例是从 release-1.4 切换到 release-1.3) 首先将 $GOAPTH/src/github.com/hyperledger/ 下1.4版本的fabric-samples给删 ...
- 怎样绑定this
有三种方法: 1. Function.prototype.call(); 2. Function.prototype.apply(); 3. Function.prototype.bind(); ...
- (一)SpringMvc简介以及第一个springmvc工程
一.SpringMVC是什么? springmvc是Spring的一个模块,提供web层解决方案(就与MVC设计架构) 如上图, DispatcherServlet:前端控制器,由SpringMVC提 ...
- 在论坛中出现的比较难的sql问题:5(row_number函数 分页、随机返回数据)
原文:在论坛中出现的比较难的sql问题:5(row_number函数 分页.随机返回数据) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路. 1.在inner join后, ...
- java调用.net的webservice接口
要调用webservice,首先得有接口,用已经写好的接口地址在myEclipse的目标project中,右键->new web service client-> 选择JAX-WS方式,点 ...
- 正则限制input负数输入
//直接在input标签内加入下面两个事件处理程序即可 onkeyup="this.value=this.value.replace(/\D|^0/g,'')" onafterpa ...
- ios编程时常见问题总结
(1)在UIViewController里面使用了timer,会使得controller被retain,因此在viewdisapper时应将timer置为nil,否则controller的deallo ...
- sudo命令 sudoers文件
超级用户权限 # Host alias specification Host_Alias HA = 192.168.1.1, 192.168.1.2 # User alias specificatio ...
- Linux磁盘管理——swap分区
转自:Linux Swap交换分区设置 对swap分区的误解 一种流行的.以讹传讹的说法是,安装Linux系统时,交换分区swap的大小应该是内存的两倍.也就是说,如果内存是2G,那么就应该分出4G的 ...