1. 程式人生 > 其它 >#454. Minimum Or Spanning Tree

#454. Minimum Or Spanning Tree

#454. Minimum Or Spanning Tree

題目描述

給出\(n\)個點, \(m\)條邊的無向圖, 每條邊連線\(u,v\)兩個端點,邊權為\(w\), 求圖的生成樹的最小代價。

在這道題中, 我們定義一棵生成樹的代價為他所有邊的邊權按位或得到的值。

輸入格式

第一行兩個數字 \(n\)\(m , n\) 表示點數,$m $表示圖的邊數。

接下來 \(m\) 行 , 每行三個整數 \(u,v,w\),表示點 \(u\) 和點\(v\) 之間存在一條邊權為 \(w\) 的邊。

輸出格式

一行, 描述生成樹的最小代價。

樣例輸入

5 7
4 2 7
2 5 8
3 4 2
3 2 1
2 4 2
4 1 2
1 2 2

樣例輸出

10

資料規模

所有資料保證 \(1≤u,v≤n≤2⋅10^5,n−1≤m≤4⋅10^5,1≤w≤10^9\)且至少存在一棵生成樹。

題目分析

先假設\(ans\)為最大值,按位列舉看看當前位是否能為\(0\),把為\(0\)的放在一起,通過並查集檢測是否構成聯通圖。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+7;
struct Edge {
	ll s,f;
	ll val;
};
inline int read(){
    int This=0,F=1; char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') F=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        This=(This<<1)+(This<<3)+ch-'0';
        ch=getchar();
    }
    return This*F;
}
int fa[N];
inline int find(int x) {
	if(x==fa[x])
		return x;
	fa[x] = find(fa[x]);
	return fa[x];
}
inline void unoin(Edge x) {
	ll x_fa = find(x.s);
	ll y_fa = find(x.f);
	fa[x_fa] = y_fa;
}
inline bool check(int n) {
	int t = find(1);
	for(int i = 1 ; i <= n ; i++)
		if(find(i)!=t)
			return 0;
	return 1;
}
int main() {
//	freopen("input.txt","r",stdin);
//	freopen("output.txt","w",stdout);
	int n,m;
	scanf("%d%d",&n,&m);
	vector<Edge>e;
	for(int i = 1 ; i <= m ; i++) {
		ll s = read(),f= read(),val= read();
		e.push_back({s,f,val});
	}
	ll ans = (1ll<<32)-1;
	for(int i = 31 ; i>=0 ; i--) {
		ans -= (1ll<<i);
		vector<Edge>te;
		memset(fa,0,sizeof(fa));
		for(int i = 1 ; i <= n ; i++)
			fa[i] = i;
			
		for(int j = 0 ; j < e.size() ; j++) {
			if((e[j].val | ans) <= ans) { //希望篩出該位為0
				te.push_back(e[j]);
				unoin(e[j]);
			}
		}
		if(check(n))
			e = te;
		else ans += (1ll<<i);
	}
	printf("%lld",ans);
	return 0;
}