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