UVA1627 团队分组 Team them up! 题解
Solution
经典题。
考虑在同一个团队内的人互相是朋友关系,不妨转化一下:把不是朋友的人相互连边,那么此时同一个团队内的人互相之间则没有边。
考虑对建出来的图跑染色法,则我们会得到有数个二分图的图。考虑无解的情况:即在跑染色法时无解,则原图无解。
考虑共有 \(cnt\) 个二分图,第 \(i\) 个二分图左半部分的数量为 \(l_i\),右半部分的数量为 \(r_i\)。
此时不妨设 \(f_{i,j}\) 表示在前 \(i\) 个二分图中,在前 \(i\) 个二分图中给最终的二分图的左半部分选择了 \(j\) 个人是否可行。还需要一个辅助数组 \(g_{i,j}\) 表示给最终二分图的左半部分选择的是第 \(i\) 个二分图的左还是右半部分。
不难推出状态转移方程:
-
\(f_{i,j+l_i}=f_{i-1,j}\),此时 \(g_{i,j+l_i}=0\),表示选择了左半部分。
-
\(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;
}

浙公网安备 33010602011771号