zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第五场) maximum clique 1

    题意:给出n个不相同的数,问选出尽量多的数且任两个数字二进制下不同位数大于等于2。

    解法:能想到大于等于2反向思考的话,不难发现这是一个二分图,那么根据原图的最大团等于补图的最大独立点集,此问题就变成 任两个二进制位数相差等于1之间连边(这就是补图),然后求这个图的最大独立点集,仔细观察发现补图是个二分图。那么就可以得到最大独立点集=n-最大匹配。

    那么怎么构造一个可行方案呢?参考《算法竞赛进阶指南》的办法,1求出最大匹配  2从左边非匹配点出发跑增广路同时把路上的点标记 3最后左边非匹配点和右边匹配点组成最小点覆盖。    那么最大独立点集就是除了最小点覆盖的点啦。

    以前没写过构造最大独立点集,这题写了记录下来以免以后忘了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e3+10;
    typedef long long LL;
    int n,col[N],match[N],a[N];
    map<LL,int> mp;
    vector<int> G[N];
    
    void dfs1(int x,int c) {
        col[x]=c;
        for (int i=0;i<G[x].size();i++) {
            int y=G[x][i];
            if (!col[y]) dfs1(y,3-col[x]);
        }
    }
    
    bool vis[N],Ans[N];
    bool dfs(int x) {
        vis[x]=1;
        for (int i=0;i<G[x].size();i++) {
            int y=G[x][i];
            if (!vis[y]) {
                vis[y]=1;
                if (!match[y] || dfs(match[y])) {
                    match[y]=x; match[x]=y;  
                    return 1;
                }
            }
        }
        return 0;
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        for (int i=0;i<=33;i++) mp[1LL<<i]=1;
        for (int i=1;i<=n;i++)
            for (int j=i+1;j<=n;j++)
                if (mp.count(a[i]^a[j])) G[i].push_back(j),G[j].push_back(i);
        for (int i=1;i<=n;i++)
            if (!col[i]) dfs1(i,1);         
        
        int ans=0;
        for (int i=1;i<=n;i++) {
            if (col[i]==2) continue;
            memset(vis,0,sizeof(vis));
            if (dfs(i)) ans++;
        }    
        cout<<n-ans<<endl;
        
        memset(vis,0,sizeof(vis));
        for (int i=1;i<=n;i++)
            if (col[i]==1 && !match[i]) dfs(i);
        memset(Ans,0,sizeof(Ans));    
        for (int i=1;i<=n;i++)
            if (col[i]==1 && !vis[i] || col[i]==2 && vis[i]) Ans[i]=1;
        for (int i=1;i<=n;i++)
            if (!Ans[i]) printf("%d ",a[i]);            
        return 0;
    } 
  • 相关阅读:
    MOSS 2010 修改管理员密码 欧阳锋
    MOSS2010 中“找不到位于xxxx的web应用程序”的解决办法 欧阳锋
    MSSQL 2008 无法修改表问题的解决 欧阳锋
    不是每个在你身上拉屎的都是你的敌人 欧阳锋
    笑一笑 欧阳锋
    隐藏MOSS2010 左边的导航 欧阳锋
    爱情与婚姻的区别 欧阳锋
    两年后,我们怎么办
    C#控件的闪烁问题解决方法总结
    Linux内核编译配置过程
  • 原文地址:https://www.cnblogs.com/clno1/p/11438094.html
Copyright © 2011-2022 走看看