[Nowcoder] 2019 Niuke Summer Multi-school Training Camp (Fifth Session) F maximum clique 1 | Bipartite graph, maximum independent set

Main idea:

Given a sequence 数字各不相同,, the largest set is required to be selected so that the 二进制representations of any two numbers in this set are 两位及以上different

Question idea:

Obviously the biggest group problem

Maximum clique = maximum independent set of complement

In other words, for this sequence, use the complementary graph to build the edge:如果两个数相差只有1位就连边

At this time it is expressed as: suppose x, yx, yx,y is connected, thenxxxyyy cannot appear in the same set at the same time

That is, the conversion is to find the maximum independent set of the graph, of course, the premise of the maximum independent set is a bipartite graph.

Then the numbers are different, and only one bit is different, then n 2 n^2n2 After the map is built, it is obviously a bipartite graph

First, color the bipartite graph, connect the source point with white, and connect the sink point with the black edge, and then run the maximum matching. Of course, this part can be omitted. Observe that, because there is only one bit different, so when the two numbers are 二进制represented, 1 is When the number of parities is the same, it is impossible to connect edges, so according to 1 1The parity of 1 number is directly divided into2 2Type 2 is fine

Finally n − max n-maxnm a x is the answer,max maxm A X refers to the largest match
:最大独立集 = n - 最小点覆盖
:最小点覆盖 = 最大匹配

关于路径还原:

This is very strange. First, we must find the minimum point coverage, and remove the points covered by the minimum point, which is the largest independent set:最小点覆盖,覆盖了所有边,那么这些点撤去之后,所有边都会缺失一个或者两个端点,从而构成独立集

Consider how to restore the minimum point coverage:

For dinic dinicd i n i c algorithm lastbfs bfsb f s is an augmentation of the residual network. If there is an augmented road, then the set on the right must be selected to dismantle this augmented road, because the number of points is1 1less1 , and then count the points with the largest matching on the left to form a minimum point coverage, remove these points from n points, and become the maximum independent set

Code:

/*** keep hungry and calm CoolGuang!  ***/
/*#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)*/
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17+7;
const ll maxn = 5e5+700;
const int mod= 998244353;
const int up = 1e9;
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int num[maxn],b[maxn];
///网络流
struct Dinic{
    
    
    ll cnt = 2;
    struct Edge{
    
    
        int e,next;
        ll w;
    };
    int _S,_T,N;
    int head[maxn],d[maxn],cur[maxn];
    Edge edge[maxn];
    void _inint(int s,int t,int n){
    
    ///n包括S与T
        memset(head,0,sizeof(head));
        cnt = 2;
        _S = s,_T = t,N = n;
    }
    void addedge(int u,int v,ll w){
    
    
        edge[cnt] = Edge{
    
    v,head[u],w};
        head[u] = cnt++;
    }
    void Add(int u,int v,ll w){
    
    
        addedge(u,v,w);addedge(v,u,0);
        ///输出建图 用于debug 一般情况注释
        //printf("%c %lld=[%d %d]%c\n",u==_S?'S':' ',w,u,v,v==_T?'T':' ');
    }
    bool bfs(){
    
    
        for(int k=0;k<=N;k++) d[k] = 0;
        queue<int>q;q.push(_S);d[_S] = 1;
        while(!q.empty()){
    
    
            int u = q.front();q.pop();
            for(int i=head[u];i;i=edge[i].next){
    
    
                int e = edge[i].e;
                if(edge[i].w <= 0||d[e]) continue;
                d[e] = d[u]+1;
                q.push(e);
            }
        }
        for(int k=0;k<=N;k++) cur[k] = head[k];
        return (d[_T] != 0);
    }
    ll dfs(int u,ll flow){
    
    
        if(u == _T)return flow;///找到可行流
        for(int &i=cur[u];i;i=edge[i].next){
    
    
            int e = edge[i].e;
            if(d[e]!=d[u]+1||edge[i].w<=0) continue;
            ll temp = dfs(e,min(flow,edge[i].w));
            if(temp<=0) continue;
            edge[i].w -= temp;
            edge[i^1].w += temp;
            return temp;
        }
        return 0;
    }
    ll MaxFlow(){
    
    
        ll maxflow = 0,delta = 0;
        while(bfs()){
    
    
            while(delta = dfs(_S,INF)) maxflow+= delta;
        }return maxflow;
    }
    void AC(){
    
    
        for(int i=1;i<=n;i++)
            if((d[i] == 0)^b[i]) printf("%d ",num[i]);
        return;
    }
}g;
int main(){
    
    
    read(n);
    g._inint(0,n+1,n+1);
    for(int i=1;i<=n;i++){
    
    
        read(num[i]);
        b[i] = __builtin_parity(num[i]);
        if(b[i]) g.Add(0,i,1);
        else g.Add(i,n+1,1);
    }
    for(int i=1;i<=n;i++){
    
    
        for(int k=i+1;k<=n;k++){
    
    
            int temp = num[i]^num[k];
            if(!(temp&(temp-1))){
    
    
                if(b[i]) g.Add(i,k,1);
                else g.Add(k,i,1);
            }
        }
    }
    printf("%lld\n",n-g.MaxFlow());
    g.AC();
    return 0;
}

/***
5 7
1 2 3 4 5
1 2
2 3
3 4
4 5

3 1
3 2
2 1 5
1 2
2 1 3
3 1
3 5
****/

Guess you like

Origin blog.csdn.net/qq_43857314/article/details/111744002