【Kruskal算法】(最小生成树)

【Kruskal算法】

模版题 https://www.acwing.com/file_system/file/content/whole/index/content/4386/

思路

(1)将所有边按权重从小到大排序
(2)枚举每条边a-b 权重为c
	if(a,b不连通) //并查集思想
		将这条边加入集合中

模版代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
//不需要邻接表/邻接矩阵->结构体存边即可
//注意这里虽然是无向图 但是因为存每一条连边 所以不需要存两次
int n,m;
int p[N];//并查集 
struct Edge{
	int a,b,w;
	bool operator< (const Edge &W)const{
		return w<W.w;
	}
}edges[N];
int find(int x){
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cin>>n>>m;
      for(int i=0;i<m;i++){
      	int a,b,w;
		cin>>a>>b>>w;
		edges[i]={a,b,w};
	}
	sort(edges,edges+m);
	//初始化并查集 
	for(int i=1;i<=n;i++) p[i]=i;
	//从小到大枚举所有边 
	int res=0,cnt=0;
	for(int i=0;i<m;i++){
		int a=edges[i].a,b=edges[i].b,w=edges[i].w;
		a=find(a);
		b=find(b);
		if(a!=b){
			p[a]=b;//两集合合并 
			res+=w;//求权重和 
			cnt++;//当前加了多少条边 
		}
	}
	if(cnt<n-1) cout<<"impossible";//该图不连通
	else cout<<res; 
      return 0;
}

最大生成树

以下两种方法挑一种即可
(1)优先队列把从小到大改成从大到小
(2)把边权改成相反数

题目积累

黑白树

https://acm.hdu.edu.cn/contest/problem?cid=1202&pid=1008

题目大意

QQ_1777475266929

思路

一棵树的节点树为n,那么他的边数一定为n-1
将白边边权设为1,黑边边权设为0
注意这里是生成树:需要包含所有节点,边数固定为n-1
那么求最小生成树时,可以得到白边的下限,反之求最大生成树可以求得白边上限
由于边数固定,白边固定可自动推黑边个数:那么答案就是白边上下限

代码

int n,m;
struct DSU {
    vector<int> fa;
    DSU(int n) : fa(n + 1) {
        iota(fa.begin(), fa.end(), 0);
    }
    int get(int x) {
        while (x != fa[x]) {
            x = fa[x] = fa[fa[x]];
        }
        return x;
    }
    bool merge(int x, int y) { // 设x是y的祖先
        x = get(x), y = get(y);
        if (x == y) return false;
        fa[y] = x;
        return true;
    }
    bool same(int x, int y) {
        return get(x) == get(y);
    }
};
struct Tree {
    using TII = tuple<int, int, int>;
    int n;
    priority_queue<TII, vector<TII>, greater<TII>> ver;

    Tree(int n) {
        this->n = n;
    }
    void add(int x, int y, int w) {
        ver.emplace(w, x, y); // 注意顺序
    }
    int kruskal() {
        DSU dsu(n);
        int ans = 0, cnt = 0;
        while (ver.size()) {
            auto [w, x, y] = ver.top();
            ver.pop();
            if (dsu.same(x, y)) continue;
            dsu.merge(x, y);
            ans += w;
            cnt++;
        }
        if(cnt < n - 1) return -1; // 输入有误,建树失败
        return ans;
    }
};
struct Tree2 {
    using TII = tuple<int, int, int>;
    int n;
    priority_queue<TII, vector<TII>, less<TII>> ver;

    Tree2(int n) {
        this->n = n;
    }
    void add(int x, int y, int w) {
        ver.emplace(w, x, y); // 注意顺序
    }
    int kruskal() {
        DSU dsu(n);
        int ans = 0, cnt = 0;
        while (ver.size()) {
            auto [w, x, y] = ver.top();
            ver.pop();
            if (dsu.same(x, y)) continue;
            dsu.merge(x, y);
            ans += w;
            cnt++;
        }
        if(cnt < n - 1) return -1; // 输入有误,建树失败
        return ans;
    }
};
void solve(){
    cin>>n>>m;
    Tree tree(n);
    Tree2 tree2(n);
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        tree.add(u,v,w);
        tree2.add(u,v,w);
    }   
    int ans=tree2.kruskal();
    if(ans==-1){
        cout<<0<<endl;
        return;
    }
    ans=ans-tree.kruskal()+1;
    cout<<ans<<endl;
}
posted @ 2025-01-12 13:34  White_ink  阅读(26)  评论(0)    收藏  举报