码迷,mamicode.com
首页 > 其他好文 > 详细

浅说——最小生成树

时间:2019-06-14 19:59:12      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:space   src   ons   include   scan   hellip   模板题   ike   mst   

图论基础知识

设有图G(V,E).

w(u,v)表示边(u,v)的权。

生成树是G的极小连通子图,它包含原图的n个点和n-1条边,且是连通的。

若存在树T,使得边权之和W(T)最小,则T为最小生成树。

技术图片

例:(来了来了…)

要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信。

但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同。

次要目标是要使铺设光缆的总费用最低。

 这里讲两种方法:

Kruskal算法(克鲁斯卡尔):贪心策略,不断加边

Prim算法(普里姆):贪心策略,不断加点

Kruskal算法:

先构造一个只含 n 个顶点,而边集为空的子图。(开始加边)

之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取(已经到过了)

而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。

从最短边开始加,若未经历节点,则加入树。

度娘

伪代码

 

sort(e+1,e+m+1);
初始化MST=NULL;
初始化各点各自为一个集合;
for(int i=0;i<m;i++)
{
if(e[i].u和e[i].v不在一个集合) { 将e[i]加入MST; 合并e[i].u和e[i].v所在的集合; }
}

该算法中关键在于解决判断u,v是否在同一集合和将其合并的操作,这里我们使用一种简单高效的方法:并查集

并查集是一种树型的数据结构,用于处理一些点所在集合的合并及查询问题。常常在使用中以森林来表示。

算法步骤

初始化:把每个点所在集合初始化为其自身。

查找:查找元素所在的集合,即根节点。

合并:将两个元素所在的集合合并为一个集合。合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。

void chushi()
{//初始化
for(int i=0;i<n;i++)father[i]=i;
}

int find(int x)
{//查找
if(father[x]==x)return x;
return father[x]=find(father[x]);
}//路径压缩

void unionset(int x,int y)//合并
{
 int fx=find(x);//查找x的所在树的根
 int fy=find(y);//查找y的所在树的根
 if(fx!=fy)father[fx]=fy;//将x所在集合与y所在集合合并
}

自己拿演草纸推论一下就出来了

RQ193 造路行动

模板题:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1005;
int n,m,ans;
int fa[maxn];
struct edge{
    int x,y,v;
}e[maxn*maxn];
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
bool cmp(struct edge a,struct edge b)
{
    return a.v<b.v;
}
void kruskall()
{
    int cnt=0;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        if(cnt==n-1) break;        
        int fx=find(e[i].x);
        int fy=find(e[i].y);
        if(fx!=fy)
        {
            fa[fx]=fy;            
            cnt++;
            ans+=e[i].v;
        }        
    }
    printf("%d",ans);
}
int main()
{
    int x,y,a;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) 
    {
        scanf("%d%d%d",&x,&y,&a);
        e[i].x=x;
        e[i].y=y;
        e[i].v=a;            
    }
    kruskall();
    return 0;
}

浅说——最小生成树

标签:space   src   ons   include   scan   hellip   模板题   ike   mst   

原文地址:https://www.cnblogs.com/mzyczly/p/11025043.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!