UVA1627 团队分组 Team them up! 题解

Solution

经典题。

考虑在同一个团队内的人互相是朋友关系,不妨转化一下:把不是朋友的人相互连边,那么此时同一个团队内的人互相之间则没有边。

考虑对建出来的图跑染色法,则我们会得到有数个二分图的图。考虑无解的情况:即在跑染色法时无解,则原图无解。

考虑共有 \(cnt\) 个二分图,第 \(i\) 个二分图左半部分的数量为 \(l_i\),右半部分的数量为 \(r_i\)

此时不妨设 \(f_{i,j}\) 表示在前 \(i\) 个二分图中,在前 \(i\) 个二分图中给最终的二分图的左半部分选择了 \(j\) 个人是否可行。还需要一个辅助数组 \(g_{i,j}\) 表示给最终二分图的左半部分选择的是第 \(i\) 个二分图的左还是右半部分。

不难推出状态转移方程:

  1. \(f_{i,j+l_i}=f_{i-1,j}\),此时 \(g_{i,j+l_i}=0\),表示选择了左半部分。

  2. \(f_{i,j+r_i}=f_{i-1,j}\),此时 \(g_{i,j+r_i}=1\),表示选择了右半部分。

最后利用辅助数组递归输出即可。

注意初始化以及建图用 vector。同学实测用链式前向星会 TLE?

#include<bits/stdc++.h> 
#define ll long long 
#define x first 
#define y second 
#define il inline 
#define debug() puts("-----") 
using namespace std; 
typedef pair<vector<int>,vector<int>> PII; 
il int read(){ 
	int x=0,f=1; char ch=getchar(); 
	while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 
	return x*f; 
} 
const int N=110; 
int n; 
bool flg;  
int cnt=0; 
PII vec[N]; 
int col[N]; 
int g[N][N]; 
bool f[N][N]; 
bool st[N][N]; 
vector<int> e[N]; 
vector<int> t1,t2; 
il void dfs(int u,int w){  
	if(~col[u]){ 
		if(col[u]!=w) flg=false; 
		return ; 
	} col[u]=w; 
	if(!w) vec[cnt].x.push_back(u); 
	else vec[cnt].y.push_back(u); 
	for(auto to:e[u]) dfs(to,w^1); 
} 
il void print(int i,int x){ 
	if(!x) return ; 
	if(!g[i][x]){ 
		for(auto u:vec[i].x) t1.push_back(u); 
		for(auto u:vec[i].y) t2.push_back(u); 
		print(i-1,x-vec[i].x.size()); 
	} else{ 
		for(auto u:vec[i].y) t1.push_back(u); 
		for(auto u:vec[i].x) t2.push_back(u); 
		print(i-1,x-vec[i].y.size()); 
	} 
} 
il void solve(){ 
	n=read(); 
	cnt=0,flg=true; 
	t1.clear(),t2.clear(); 
	for(int i=0;i<=n;i++) 
		for(int j=0;j<=n;j++) 
			f[i][j]=st[i][j]=false,g[i][j]=-1; 
	for(int i=1,x;i<=n;i++){ 
		while(true){ 
			x=read(); 
			if(!x) break; 
			st[i][x]=true; 
		} col[i]=-1,e[i].clear(); 
		vec[i].x.clear(),vec[i].y.clear(); 
	} for(int i=1;i<=n;i++){ 
		for(int j=i+1;j<=n;j++){ 
			if(!st[i][j]||!st[j][i]) e[i].push_back(j),e[j].push_back(i); 
		} 
	} for(int i=1;i<=n;i++) if(col[i]==-1) cnt++,dfs(i,0); 
	if(!flg){ puts("No solution\n"); return ; } 
	f[0][0]=true; 
	for(int i=1;i<=cnt;i++){ 
		for(int j=0;j<=n;j++){ 
			if(!f[i-1][j]) continue; 
			g[i][j+vec[i].x.size()]=0; 
			g[i][j+vec[i].y.size()]=1; 
			f[i][j+vec[i].x.size()]=true; 
			f[i][j+vec[i].y.size()]=true; 
		} 
	} int ans=n,res=0; 
	for(int i=1;i<=n;i++) if(f[cnt][i]&&abs(n-2*i)<ans) ans=abs(n-2*i),res=i; 
	print(cnt,res); 
	printf("%d ",(int)t1.size()); 
	for(auto u:t1) printf("%d ",u); puts(""); 
	printf("%d ",(int)t2.size()); 
	for(auto u:t2) printf("%d ",u); puts("\n"); 
} 
signed main(){ 
	int T=read();  
	while(T--) solve();  
	return 0; 
} 
posted @ 2024-03-07 13:36  Celestial_cyan  阅读(37)  评论(0)    收藏  举报