蓝精灵的请求「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();
}

原文地址:https://www.cnblogs.com/ilverene/p/11620107.html