首页 > 其他分享 >Team them up!题解

Team them up!题解

时间:2022-12-08 11:11:46浏览次数:39  
标签:二分 them int 题解 void up 队伍 Team

Team them up!

题面

你的任务是按照以下要求将一些人员划分到两个队伍中。

每个人都属于其中的一个队伍。
每个队伍至少包含一个人。
每个人都认识几个人,而同一个队伍中的人必须两两认识。
两个队伍的人数尽可能的接近。 这个任务可能有多组解或无解,你只需要输出其中的任意一种或者宣布无解。

分析

不难发现,两个人不能处于同一队伍,当且仅当两人不互相认识。然后又恰好是一个分两个队的问题,考虑二分图。我们就可以将互相认识的两个人连边进行二分图,跑一次二分图。由于图不一定连通,于是我们就得到了若干个连通的子图,通过二分图可以确定这两个子图的两部分,于是我们的问题就变成了:从\(num\)个二元组中,每个二元组选其中一个数,使得其和最接近\(\frac{n}{2}\),由此,引导我们想到特殊的分组背包。具体的,将每个二元组视为一组物品,我们的问题就是:给定若干个组物品,每组有两个,每个物品的重量与价值相等,有一个容量为\(\frac{n}{2}\)的背包,要求使得装入的价值最大。背包模板即可,本题要求输出方案,记得保存DP转移路径。

#include<bits/stdc++.h>
using namespace std;
#define N 500
#define M 500000
int head[M],nxt[M],ver[M],a[N][N],n,m,tot=1;
int v[M][5],w[M],siz[M],c[M],num,f[N][N],pos[M];
int ans[M];
struct node{
	int i,j,id;
}h[N][N];
void add(int u,int v){
	nxt[++tot]=head[u],ver[head[u]=tot]=v;
}
void init(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int x;
		while(cin>>x&&x){
			a[i][x]=1;
		}
	}
}
void build(){
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			if(a[i][j]&&a[j][i])continue;
			add(i,j);
			add(j,i);
		}
	}
}
void dfs(int u,int color,int num){
	pos[u]=num;
	v[num][color]++;
	c[u]=color;
	for(int i=head[u];i;i=nxt[i]){
		int v=ver[i];
		if(c[v]){
			if(c[v]==c[u]){
				cout<<"No solution"<<endl;
				exit(0);
			}
			continue;
		}
		dfs(v,color==1?2:1,num);
	}
}
void get(int i,int j){//第i组状态为j 
	if(i<1)return ;
	int id=h[i][j].id;
	for(int k=1;k<=n;k++){
		if(pos[k]==i&&c[k]==id){
			ans[k]=1;
		}
	}
	get(i-1,h[i][j].j);
}
void solve(){	
	for(int i=1;i<=n;i++)
		if(!c[i])dfs(i,1,++num);
	memset(f,0xcf,sizeof f);
	f[0][0]=0;
	for(int i=1;i<=num;i++){
	//	cout<<v[i][1]<<" "<<v[i][2]<<endl;
		for(int j=n/2;j>=v[i][1];--j){
			if(f[i][j]<f[i-1][j-v[i][1]]+v[i][1]){
				f[i][j]=f[i-1][j-v[i][1]]+v[i][1];
				h[i][j]={i-1,j-v[i][1],1};
			} 
		}
		for(int j=n/2;j>=v[i][2];--j){
			if(f[i][j]<f[i-1][j-v[i][2]]+v[i][2]){
				f[i][j]=f[i-1][j-v[i][2]]+v[i][2];
				h[i][j]={i-1,j-v[i][2],2};
			} 
		}
	}
}
void print(){
	int ans1=0;
	for(int i=1;i<=n;i++){
		if(ans[i])ans1++;
	}
	cout<<ans1;
	for(int i=1;i<=n;i++){
		if(ans[i])cout<<" "<<i;
	}
	cout<<endl<<n-ans1;
	for(int i=1;i<=n;i++){
		if(!ans[i])cout<<" "<<i;
	}
}
int main(){
	ios::sync_with_stdio(false);
	init();
	build();
	solve();
	get(num,n/2);
	print();
	return 0;
}

标签:二分,them,int,题解,void,up,队伍,Team
From: https://www.cnblogs.com/oierpyt/p/16965532.html

相关文章