UVA1627 团队分组 Team them up! 题解

Solution

经典题。

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

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

考虑共有 cnt 个二分图,第 i 个二分图左半部分的数量为 li,右半部分的数量为 ri

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

不难推出状态转移方程:

  1. fi,j+li=fi1,j,此时 gi,j+li=0,表示选择了左半部分。

  2. fi,j+ri=fi1,j,此时 gi,j+ri=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 @   Celestial_cyan  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示