题解 P1285 【队员分组】

题目链接

Solution 队员分组

题目大意:每个都有一些认识的,(A)认识(B)不一定有(B)认识(A),你要把所有的人分成两个队伍,要求同一队伍内的人必须两两认识,在这前提上使得两队的人数尽量接近,求分组方案

二分图,背包


分析:必须两两认识不好处理,我们可以把不认识的人连上边,这样就变成了同一队伍内的人之间没有边了

我们发现在这种情况下不同连通分量的人互不影响因此可以分别计算

对于连通分量内的点,我们要把它黑白染色,并且同一颜色的点之间没有边,这就是二分图的定义,我们一次(bfs)就可以做到,并且如果任意连通分量无解则整个问题无解

然后使得两个队伍的人数接近,我们发现一个连通分量的黑点可以有两种情况,因此我们跑一个布尔背包,从(n/2)枚举求一下能不能拼出(x)个黑点就可以了

毒瘤的双倍经验题

#include <cstdio>
#include <cctype>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 128;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
vector<int> G[maxn],vec[maxn][2],ans[2];
inline void addedge(int from,int to){G[from].push_back(to);}
int n,tmp[maxn][maxn],f[maxn][maxn],opt[maxn][maxn],vis[maxn],col[maxn],vec_tot;
inline bool bfs(int s){
	queue<int> Q;Q.push(s);vis[s] = 1;
	vec_tot++;
	while(!Q.empty()){
		int u = Q.front();Q.pop();
		vec[vec_tot][col[u]].push_back(u);
		for(int v : G[u])
			if(!vis[v])col[v] = col[u] ^ 1,vis[v] = 1,Q.push(v);
			else if(col[v] == col[u])return false;
	}
	return true;
}
inline void solve(){
	n = read();
	for(int u = 1,v;u <= n;u++)
		while((v = read()))tmp[u][v] = 1;
	for(int u = 1;u <= n;u++)
		for(int v = u + 1;v <= n;v++)
			if(!(tmp[u][v] && tmp[v][u]))addedge(u,v),addedge(v,u);
	for(int i = 1;i <= n;i++)
		if(!vis[i] && !bfs(i)){
			puts("No solution");
			return;
		}
	f[0][0] = 1;
	for(int i = 1;i <= vec_tot;i++)
		for(int j = 0;j <= n;j++){
			if(j >= vec[i][0].size() && f[i - 1][j - vec[i][0].size()])f[i][j] = 1,opt[i][j] = 0;
			if(j >= vec[i][1].size() && f[i - 1][j - vec[i][1].size()])f[i][j] = 1,opt[i][j] = 1;
		}
	int now;
	for(int i = n >> 1;i >= 0;i--)
		if(f[vec_tot][i]){now = i;break;}
	for(int i = vec_tot;i >= 1;i--){
		for(auto x : vec[i][opt[i][now]])ans[0].push_back(x);
		for(auto x : vec[i][opt[i][now] ^ 1])ans[1].push_back(x);
		now -= vec[i][opt[i][now]].size();
	}
	sort(ans[0].begin(),ans[0].end());
	sort(ans[1].begin(),ans[1].end());
	printf("%d ",(int)ans[0].size());
	for(auto x : ans[0])printf("%d ",x);
	putchar('
');
	printf("%d ",(int)ans[1].size());
	for(auto x : ans[1])printf("%d ",x);
	putchar('
');
}
int main(){
	solve();
}
原文地址:https://www.cnblogs.com/colazcy/p/11792411.html