题意:
给出一个全然二分图中的一些边。求这个全然二分图中最多还有多少条边。
点数<=10000;
题解:
BC的pre test太坑爹了!
显然假设想让边数最多,两边的点数越均衡越好。
考虑到给出的图可能是不连通的,我用了并查集来维护这些点集。
(和图上染色的算法就差了一个反ackerman函数可是省了存边深搜的麻烦)
这样处理之后,就得到了一些二分图,之后就是将这些二分图组合起来,得到一个边数最大的二分图;
能够用bool背包处理。可是最坏复杂度是O(n^2)的,这里用bitset来优化dp。
能够把bitset理解为一个bool数组。而且是一个支持数组间位运算的数组。
这些运算的复杂度是O(n/32)。dp的复杂度也就降到了O(n^2/32) (实际上似乎更快一些?)。
dp的详细处理见代码吧,整体来说还是十分好用的;
加权的并查集有点绕。
。
写挂了一次;
代码:
#include<bitset> #include<stack> #include<stdio.h> #include<string.h> #include<algorithm> #define N 11000 using namespace std; int f[N]; bool val[N]; int hdu[N][2]; bitset<N>bs,t; int find(int x) { if(f[x]==x) return x; else { int t=find(f[x]); val[x]=val[x]^val[f[x]]; f[x]=t; return t; } } int main() { int c,T,n,m,i,j,k,x,y,fx,fy,cnt; scanf("%d",&T); for(c=1;c<=T;c++) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) f[i]=i,val[i]=0; memset(hdu,0,sizeof(hdu)); for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); fx=find(x),fy=find(y); if(fx!=fy) f[fy]=x,val[fy]=1; } for(i=1;i<=n;i++) { fx=find(i); hdu[fx][val[i]]++; } for(i=1,cnt=0;i<=n;i++) { if(hdu[i][0]||hdu[i][1]) { cnt++; swap(hdu[i][0],hdu[cnt][0]); swap(hdu[i][1],hdu[cnt][1]); } } bs=0; bs[0]=1; for(i=1;i<=cnt;i++) { t=bs; bs|=t<<hdu[i][0]; bs|=t<<hdu[i][1]; if(bs[n/2]) break; } for(i=0;i<=n/2;i++) { if(bs[n/2+i]) { i=n/2+i; break; } if(bs[n/2-i]) { i=n/2-i; break; } } printf("%d ",(n-i)*i-m); } return 0; }