树 并查集

//二叉树的父节点是k
//那么它的左儿子的编号就是2*k 右儿子是2*k+1  左儿子或右儿子是那么父节点是x/2
//如果一颗完全二叉树有N个节点 那么这个完全二叉树的高度是logn 
 

2.并查集

并查集通过一个维数组来实现,其本质是维护一个森林 刚开始的时候 森林的每个点都是孤立 的,也可以理解为每个点就是一颗只有一个结点的树,之后通过一些条件 逐渐将这些树合并成一颗大树,合并过程中遵守靠左原则 和擒贼先擒王原则  在每次判断两个节点是否已经在同一颗树的时候(也就是同一集合)也要注意必须求其根源 ,中间父亲节点是不能说明问题的 必须找到其祖宗(树的根结点),判断两个节点的祖宗是否是同一个根结点才行。

#include<iostream>
using namespace std;
int f[1000] = { 0 }, n, m, k, sum = 0;
//这里是初始化 非常的重要 数组里面存的是中间数组下标的编号就好了
void init() {
    for (int i = 1; i <= n; i++) {
        f[i] = i;
    }
}
//这里是找爹的递归函数 不停的去找爹 直到找到祖宗为止 其实就是去找犯罪团伙人的最高领导人 擒贼先擒王原则
int getf(int v) {
    if (f[v] == v)return v;
    else {
    //这里是路径压缩 每次在函数返回的时候 顺带把路上遇到的人的boss改为最后找到的祖宗编号 也就是犯罪团伙人的最高领导编号 这样可以提高今后找到犯罪团伙的最高领导人(其实就是树的祖先)的速度
        f[v] = getf(f[v]);
        return f[v];
    }
}
//这里是合并两子集的函数  擒贼先擒王
void merge(int v, int u) {
    int t1, t2;
    t1 = getf(v);
    t2 = getf(u);
    if (t1 != t2) {

        f[t2] = t1;
    }
}
int main(){
    int i, x, y;
    cin >> n >> m;
    init();
    for (int i = 1; i <= m; i++) {
        //开始合并犯罪团伙
        cin >> x >> y;
        merge(x, y);
    }
    //最后扫描有多少个独立的犯罪团伙
    for (int i = 1; i <= n; i++) {
        if (f[i] == i)
            sum++;
    }cout << sum;
    return 0;
}

最小生成树

库鲁斯卡尔算法+查并集

#include<iostream>
using namespace std;
struct edge {
    int u;
    int v;
    int w;
};
edge e[10];
int f[7],sum;
void quicksort(int left, int right) {
    int i = left;
    int j = right;
    if (left > right)return;
    while (i != j) {
        while (e[j].w >= e[left].w && i < j)j--;
        while (e[i].w <= e[left].w && i < j)i++;
        if (i < j)swap(e[j], e[i]);
    }
    swap(e[left], e[i]);
    quicksort(left, i - 1);
    quicksort(i + 1, right);
    return;
}
int getf(int v) {
    if (f[v] == v)return v;
    else return f[v] = getf(f[v]);
}
int merge(int u, int v) {
    int t1 = getf(u);
    int t2 = getf(v);
    if (t1 != t2) {
        f[t2] = t1;
        return 1;
    }
    return 0;
}
int main() {
    int n, m,count=0;
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        cin >> e[i].u >> e[i].v >> e[i].w;
    }
    for (int i = 1; i <= n; i++) {
        f[i] = i;
    }
    quicksort(1, m);
    for (int i = 1; i <= m; i++) {
        if (merge(e[i].u, e[i].v)) {
            count++;
            sum += e[i].w;
        }
        if (count == count - 1)break;
    }
    cout << sum;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值