最小生成树简述及模板题

先补充一点图论的基本术语(基本复制于维基百科)

1.一个图G的顶点集(点集)一般记作V(G),当不发生混淆时可简记为V。图G的为其顶点数目,亦即|V(G)|。以两个顶点u

、v为端点的边一般记作(u,v)、{u,v}或uv。一条边连接两个顶点uv时,称uv相邻。图G的边集一般记作E(G),当不发生

混淆时可简记为E。

2.一个自环是两个端点为同一顶点的边。如果有多于一条边连接同一对顶点,则它们均被称为重边。一个图的重数是重复次数最多

的边的重复次数。如果一个图不含自环或重边,则称为简单图。多数情况下,如无特殊说明,可以假定“图”总是指简单图。

3.连通图:在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图。

4.强连通图:在有向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该有向图为强连通图。

5.生成树:在无向图中,n个顶点只取n-1条边。生成树是连通图的极小联通子图,即如果再加一条边,必形成环

6.最小生成树:在所有生成树中,边代价和最小的生成树

最小生成树算法

包括prime算法和kruskal算法

一.prime算法,又称“加点法”

    1.基本思想:在一个带权连通图中,任取一顶点加入生成树中,标记,遍历所有点,找到离该点距离最近的点,标记,直至所

有顶点都加入到生成树中。(跟dijkstar思想很像)

    2.复杂度为O(n^2),n为顶点数,用邻接表存,适用于稠密图

    3.上一个模板题   杭电1233  还是畅通工程  http://acm.hdu.edu.cn/showproblem.php?pid=1233

    代码:

#include <bits/stdc++.h>

using namespace std;
const int mod = 1e9 + 7;
const int maxn = 110;
const int inf=0x3f3f3f3f;
typedef long long ll;
int mapp[maxn][maxn];
bool vis[maxn];
int dis[maxn];
int n;
int prime(int start){
    int ans=0;
    for(int i=1; i<=n; i++){
        dis[i]=mapp[start][i];//记录起点出发的距离
        vis[i]=0;
    }
    vis[start]=1;   //加入任一点(或起点)
    int noww;
    for(int i=1; i<n; i++){
        int minn=inf;
        for(int j=1; j<=n; j++){
            if(!vis[j] && dis[j]<minn){//找到距离最短的
                minn=dis[j];
                noww=j;
            }
        }
        vis[noww]=1;
        ans+=minn;
        for(int j=1; j<=n; j++){
            if(!vis[j] && dis[j]>mapp[noww][j])//加入新的点后更新距离
                dis[j]=mapp[noww][j];
        }
    }
    return ans;
}
int main() {
    int u,v,d;
    while(~scanf("%d",&n)){
        if(n==0)  break;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                mapp[i][j]=inf;
            }
        }
        for(int i=1; i<= n*(n-1)/2; i++){
            scanf("%d%d%d",&u,&v,&d);
            mapp[u][v]=d;
            mapp[v][u]=d;
        }
        int ans=prime(1);
        printf("%d\n",ans);
    }
    return 0;
}

二.kruskal算法,又称“加边法”

    1.基本思想:将边按权值从小到大排序,遍历,若该边两个端点不在一个树上,则加上,若在,则跳过继续下一条边,贪心思

想,并查集实现

    2.时间复杂度O(mlogm),m为边数

    3.还是上一个题

    代码:

#include <bits/stdc++.h>

using namespace std;
const int mod = 1e9 + 7;
const int maxn = 1e4 + 10;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int n, m;
struct node {
    int u, v, val;
} s[maxn];
int fa[maxn], deep[maxn];

bool cmp(node x, node y) {
    return x.val < y.val;
}

void init() {
    for (int i = 0; i <= m; i++) {
        fa[i] = i;
        deep[i] = 1;
    }
}

int findd(int x) {
    return fa[x] == x ? x : fa[x] = findd(fa[x]);//查找
}

void Union(int x, int y) {
    int fx = findd(x);
    int fy = findd(y);
    if (deep[x] < deep[y])
        fa[fx] = fy;
    else {
        if (deep[x] == deep[y]) deep[x]++;
        fa[fy] = fx;
    }
}

int kruskal() {
    int ans = 0;
    init();
    for (int i = 1; i <= m; i++) {
        if (findd(s[i].u) != findd(s[i].v)) {
            Union(s[i].u, s[i].v);
            ans += s[i].val;
        }
    }
    return ans;
}

int main() {
    while (~scanf("%d", &n)) {
        if (n == 0) break;
        m = n * (n - 1) / 2;
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &s[i].u, &s[i].v, &s[i].val);
        }
        sort(s + 1, s + 1 + m, cmp);
        int ans = kruskal();
        printf("%d\n", ans);
    }
    return 0;
}
 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值