最小生成树

分析

克鲁斯卡尔算法

  • 算法思想:将所有边按照边权最小到大排序,依次枚举所有的边,如果边的两个端点已经在同一个集合中(可连通),就continue,否则合并边的两个端点(将边权加入到答案中),直到有n-1条边参与合并为止。

  • 最后如何判断这个生成的子图是不是树?

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#include <vector>

using namespace std;
#define ll long long
#define sc(x) scanf("%d",&x)
#define scc(x, y) scanf("%d%d",&x,&y)
#define p(x) printf("%d\n",x)
#define m(x, y) (x+y)>>1
#define l(x) x<<1
#define r(x) x<<1|1
const int maxn = 1e5 + 6;
int fa[maxn];
int n;

struct Edge {
    int from, to, cost;

    bool operator<(const Edge &p) const {
        return cost < p.cost;
    }
} edge[maxn];


//找到x的掌门人
int find(int x) {
    if (x == fa[x]) return x;
    return fa[x] = find(fa[x]);//路径压缩
}

//合并x和y所在的门派
void unite(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if (fx == fy) return;
    fa[fx] = fy;
}

//查看x和y的门派是否相同
bool check(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if (fx == fy) return true;
    return false;
}

int main() {
    int m, ans, cnt;
    while (~sc(n) && n) {
        sc(m);
        //初始化
        for (int i = 1; i <= n; i++) fa[i] = i;
        ans = 0, cnt = 0;//ans为路程总和,cnt为连接的边的数量
        //读入边
        for (int i = 1; i <= m; i++) scanf("%d%d%d", &edge[i].from, &edge[i].to, &edge[i].cost);
        //对边的权值排序
        sort(edge + 1, edge + m + 1);
        
        for (int i = 1; i <= m; i++) {
            //若两点不在同一条线
            if (!check(edge[i].from, edge[i].to)) {
                ans += edge[i].cost;
                cnt++;
                unite(edge[i].from, edge[i].to);//合并
            }
        }
        //检验,打印cost之和
        if (cnt == n - 1) p(ans);
    }
    return 0;
}

题目

用多组数据,用空行隔开,每组数据第一行有两个数,n个点和m个边,接下来有m行,from,to,cost,最后以0结尾。

  • 输入示例
1 0

2 3
1 2 37
2 1 17
1 2 68

3 7
1 2 19
2 3 11
3 1 7
1 3 5
2 3 89
3 1 91
1 2 32

5 7
1 2 5
2 3 7
2 4 8
4 5 11
3 5 10
1 5 6
4 2 12

0
  • 输出示例
0
17
16
26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值