problem

【代码源 Div1 - 109】#454. Minimum Or Spanning Tree(最小生成树,边权按位或,贪心,并查集) CF1624G_算法

solution

  • 题意:生成树的代价为他所有边的边权按位或得到的值,求最小生成树
  • 贪心,一般来说,求 按位与 和 按位或 的最大值都可以从高往低逐位的贪心处理
  • 对于当前位 b 而言,若存在 n−1 条边的边权都不存在 b 且不构成环的话,那么我们可以把所有包含 b 的边都删除;若不足 n−1 条边满足之前的条件的话,则将 b 加入答案
//AC1
#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const LL maxn = 1e6+10;

int fa[maxn+10];
void init(int n){for(int i = 0; i <= n; i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}
int count(int n){int cnt=0; for(int i = 1; i <= n; i++)if(fa[i]==i)cnt++;return cnt;}

struct node{int u, v, w; }e[maxn];
int vis[maxn];

int main(){
    int n, m;  cin>>n>>m;
    for(int i = 1; i <= m; i++){
        cin>>e[i].u>>e[i].v>>e[i].w;
    }
    int ans = 0;
    for(int b = 29; b >= 0; b--){
        init(n);
        int cc = 1;
        for(int i = 1; i <= m; i++){
            if(vis[i])continue;
            if((~e[i].w>>b) & 1){
                if(find(e[i].u)!=find(e[i].v)){
                    merge(e[i].u, e[i].v);
                    cc++;
                }
            }
        }
        if(cc == n){
            for(int i = 1; i <= m; i++){
                if((~e[i].w>>b) & 1){
                    
                }else{
                    vis[i] = 1;
                }
            }
        }else{
            ans |= 1<<b;
        }
    }
    cout<<ans<<"\n";
    return 0;
}
//AC2
#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const LL maxn = 1e6+10;

int fa[maxn+10];
void init(int n){for(int i = 1; i <= n; i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}
int count(int n){int cnt=0; for(int i = 1; i <= n; i++)if(fa[i]==i)cnt++;return cnt;}

tuple<int,int,int>e[maxn<<1];

int main(){
    IOS;
    int n, m;  cin>>n>>m;
    for(int i = 1; i <= m; i++){
        cin>>get<0>(e[i])>>get<1>(e[i])>>get<2>(e[i]);
    }
    int k = 29;
    int ans = (1<<k)-1;
    for(int i = k-1; i >= 0; i--){
        init(n);
        int cc = n;
        ans ^= (1<<i);
        for(int j = 1; j <= m; j++){
            if((get<2>(e[j])|ans)==ans && find(get<0>(e[j]))!=find(get<1>(e[j]))){
                merge(get<0>(e[j]), get<1>(e[j]));
                cc--;
            }
        }
        ans ^= ((int)(cc!=1)<<i);
    }
    cout<<ans<<"\n";
    return 0;
}