蓝精灵的请求「NOIP多校联考 2019」
题意
对于给定的图,要求将其分为两张完全图。对于一种分法,其值为两张完全图边数之和。求所有分法最小值。
思路
建立原图的补图,显然这张图上相连的都是原来不能呆在同一组里的。对于补图中的每一个联通块都进行染色。
如果有两个节点在补图上相连且颜色一样,显然输出-1。
如果他们不相连但是颜色一样,那么必须放在同一组里。(如果不放在同一组里,就会出现一个与它们颜色不同的节点无处可放)
维护一个bool数组\(f[i]\)表示i人一组可不可行,统计每种颜色的数量,进行转移即可。
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T>inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T>inline void write (T x) {
if (x<0) putchar('-'),x*=-1;
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Project {
const int N=701;
const int INF=2147483647;
int n,m,ans=INF;
int G[N][N],color[N],size[2],f[N],t[N];
void dfs (int now,int col) {
color[now]=col,++size[col==1];
for (register int i=1; i<=n; ++i) {
if (i==now||G[now][i]) continue;
if (!color[i]) dfs(i,-col);
else if (color[i]==col) {
write(-1);
exit(0);
}
}
}
inline void MAIN () {
read(n),read(m);
for (register int i=1,x,y; i<=m; ++i) {
read(x),read(y);
G[x][y]=G[y][x]=1;
}
f[0]=1;
for (register int i=1; i<=n; ++i) {
if (color[i]) continue;
size[0]=size[1]=0;
dfs(i,1);
memset(t,0,sizeof(t));
for (register int j=0; j<=n; ++j) {
t[j+size[0]]|=f[j];
t[j+size[1]]|=f[j];
}
for (register int j=0; j<=n; ++j) {
f[j]=t[j];
}
}
for (register int i=0; i<=n/2; ++i) {
if (f[i]||f[n-i]) ans=min(ans,i*(i-1)/2+(n-i)*(n-i-1)/2);
}
write(ans);
}
}
int main () {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
Project::MAIN();
}