当前位置: 代码迷 >> 综合 >> 牛客第五场 F maximum clique 1 —— 最大独立集
  详细解决方案

牛客第五场 F maximum clique 1 —— 最大独立集

热度:61   发布时间:2024-01-09 10:57:26.0

题目链接:点我啊╭(╯^╰)╮

题目大意:

     n n n 个不同数,若两个数二进制位有两个以上的不同位则连边
    求最大团,并输出每个数

解题思路:

    考虑求补图的最大独立集
    则变为了两个数只有一个不同的二进制位则连边
    那么一个数最多与 30 30 30 个数连边,且不会到达上界

    观察可得这是个二分图:
    二进制位 1 1 1 的个数为奇数在左边、偶数在右边
    然后跑个最大匹配即可

    那么怎么求出最大独立集的每个数呢??
    这里采用了 d i n i c dinic dinic 的做法

    结论:在残存网络中:
     X X X部仍与 S S S相连的点 和 Y Y Y部不与 S S S相连的点 构成最大独立集

核心:最大团与最大独立集的转化

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
//#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
typedef long long ll;
using pii = pair <ll,int>;
const int inf = INT_MAX;
const int maxn = 3e5 + 10;
int n, st, ed, a[maxn], b[maxn];
int cnt, head[maxn];
int ans, dis[maxn];struct EDGE {int nxt, to, w;
} edge[maxn];void add(int u, int v, int w) {edge[cnt].nxt = head[u];edge[cnt].w = w;edge[cnt].to = v;head[u] = cnt++; // 从0开始edge[cnt].nxt = head[v];edge[cnt].w = 0;edge[cnt].to = u;head[v] = cnt++; 
}int bfs() {memset(dis,-1,sizeof(dis));dis[st] = 0;queue <int> Q;Q.push(st);while(!Q.empty()) {int u = Q.front();Q.pop() ;for(int i=head[u]; ~i; i=edge[i].nxt) {int v = edge[i].to;if(dis[v]==-1 && edge[i].w>0) {dis[v] = dis[u]+1;    //更新Q.push(v);}}}return dis[ed]!=-1;    //判断是否联通。
}int dfs(int u, int exp) {if(u==ed) return exp;    //到达终点,全部接受。int flow=0, tmp=0;for(int i=head[u]; ~i; i=edge[i].nxt) {int v = edge[i].to;    //下一个点。if(dis[v]==dis[u]+1 && edge[i].w>0) {tmp = dfs(v, min(exp, edge[i].w));    //往下进行if(!tmp) continue;exp -= tmp;    //流量限制-流量,后边有判断。flow += tmp;edge[i].w -= tmp;        //路径上的边残量减少edge[i^1].w += tmp;    //流经的边的反向边残量增加。if(!exp) break;    //判断是否在限制边缘}}return flow;
}int main() {st = maxn-1, ed = maxn - 2;cnt = ans = 0;memset(head,-1,sizeof(head));scanf("%d", &n);for(int i=1; i<=n; i++){scanf("%d", a+i);b[i] = __builtin_parity(a[i]);if(b[i]) add(st, i, 1);else add(i, ed, 1);}for(int i=1; i<=n; i++)for(int j=i+1; j<=n; j++){int x = a[i] ^ a[j];if((x&(x-1)) == 0){if(b[i]) add(i, j, 1);else add(j, i, 1);}}while(bfs()) ans+=dfs(st, inf);printf("%d\n", n - ans);for(int i=1; i<=n; i++)if((dis[i]==-1) ^ b[i])printf("%d ", a[i]);
}
  相关解决方案