考虑这张图的反图,相当于这两个集合内部没有边,这也就是二分图的限制
换言之,我们要将这张图黑白染色(不能则为-1),$x$即为某种颜色的数个数
对于一个联通块,记连通块大小为$sz$,则白色点个数为$w$或$sz-w$(交换两种颜色)
背包转移即可,时间复杂度为$o(n^{2})$,可以通过此题
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 705 4 struct ji{ 5 int nex,to; 6 }edge[N*N]; 7 bitset<N>f; 8 int E,n,m,x,y,ans,head[N],e[N][N],vis[N]; 9 void add(int x,int y){ 10 edge[E].nex=head[x]; 11 edge[E].to=y; 12 head[x]=E++; 13 } 14 int dfs(int k,int p){ 15 if (vis[k]>=0)return vis[k]==p; 16 x+=(!p); 17 y+=p; 18 vis[k]=p; 19 for(int i=head[k];i!=-1;i=edge[i].nex) 20 if (!dfs(edge[i].to,p^1))return 0; 21 return 1; 22 } 23 int c(int k){ 24 return k*(k-1)/2; 25 } 26 int main(){ 27 scanf("%d%d",&n,&m); 28 memset(head,-1,sizeof(head)); 29 for(int i=1;i<=m;i++){ 30 scanf("%d%d",&x,&y); 31 e[x][y]=e[y][x]=1; 32 } 33 for(int i=1;i<=n;i++) 34 for(int j=1;j<=n;j++) 35 if ((i!=j)&&(!e[i][j]))add(i,j); 36 memset(vis,-1,sizeof(vis)); 37 f[0]=1; 38 for(int i=1;i<=n;i++) 39 if (vis[i]<0){ 40 x=y=0; 41 if (!dfs(i,0)){ 42 printf("-1"); 43 return 0; 44 } 45 f=((f<<x)|(f<<y)); 46 } 47 ans=c(n); 48 for(int i=1;i<n;i++) 49 if (f[i])ans=min(ans,c(i)+c(n-i)); 50 printf("%d",ans); 51 }