题目大意:求一个图的最大团 图长啥样自己看题
最大团是NP难度问题 但由于这个图的特殊性 我们可以通过一些技♂巧♂搞定它
这破输入法又打了一些多余的符号……
首先我们建立反图 易知最大团=反图的最大点独立集
然后我们观察 A国奇数是一个完全图 偶数是一个完全图 于是A国顶多选出2个人
B国奇数之间没有边 偶数之间没有边 奇偶之间构成二分图
于是我们枚举A国的两个人(可以是1个人或者不选,全部枚举一遍),把B国的人与A国那两个人在反图上连边的全都BAN掉,跑最大点独立集即可
注意利用时间戳避免反复memset 否则慢到死
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 3010 using namespace std; struct abcd{ int to,next; }table[M*M>>2]; int head[M],tot; int A,B,m,ans,T1,T2; int a[M],b[M]; bool map[M][M]; int res[M],sta[M],ban[M],tim[M]; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } int Count(int x) { int re=0; while(x) x-=x&-x,++re; return re; } bool Hungary(int x) { int i; if(ban[x]==T1) return false; for(i=head[x];i;i=table[i].next) if(ban[table[i].to]!=T1&&sta[table[i].to]!=T2) { sta[table[i].to]=T2; if( tim[table[i].to]!=T1 || !res[table[i].to] || Hungary(res[table[i].to]) ) { tim[table[i].to]=T1; res[table[i].to]=x; return true; } } return false; } int Maximum_Independent_Set(int x=0,int y=0) { int i,re=0; ++T1; for(i=1;i<=B;i++) if(map[x][i]||map[y][i]) ban[i]=T1,++re; for(i=1;i<=B;i++) if(b[i]&1) { ++T2; if( Hungary(i) ) ++re; } return B-re; } int main() { int i,j,x,y; cin>>A>>B>>m; memset(map,true,sizeof map); for(i=1;i<=A;i++) scanf("%d",&a[i]); for(i=1;i<=B;i++) scanf("%d",&b[i]); for(i=1;i<=m;i++) scanf("%d%d",&x,&y),map[x][y]=0; for(i=1;i<=B;i++) if(b[i]&1) for(j=1;j<=B;j++) if(~b[j]&1) if(~Count(b[i]|b[j])&1) Add(i,j); for(i=1;i<=B;i++) map[0][i]=0; ans=Maximum_Independent_Set(); for(i=1;i<=A;i++) ans=max(Maximum_Independent_Set(i)+1,ans); for(i=1;i<=A;i++) if(a[i]&1) for(j=1;j<=A;j++) if(~a[j]&1) ans=max(Maximum_Independent_Set(i,j)+2,ans); cout<<ans<<endl; }