显然本题要先按不认识重新建立边(两者u认识v 但 v不认识u 也算不认识) 然后二分匹配,匹配成功,即可分为两组;
接下来的问题就是背包问题了,选每个连通分量里被1着色的部分,则该连通分量剩下的人只能在另一组,这样可看做 第一组比第二组多增加(num(1) - num(2)) 个人;这样
问题就是对所有连通分量的背包选择;
边界注意
#include <map>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 105;
vector<int> son[maxn],bag,st[maxn][2];
bool vis[maxn],G[maxn][maxn];
int color[maxn],n;
bool bipartite(int u,int cnt){
for(int i=1;i<=n;i++)if(G[u][i]){
int v = i;
if(color[v]){
if(color[v] == color[u]) return false;
continue;
}
color[v] = 3 - color[u];
st[cnt][color[v]-1].push_back(v);
if(!bipartite(v,cnt)) return false;
}
return true;
}
const int ADD = 101;
int d[maxn][maxn*2+4][2];
bool VIS[maxn][maxn*2+4][2];
int dp(int i,int j,int k){
if(VIS[i][j][k]) return d[i][j][k];
VIS[i][j][k] = true;
int& ans = d[i][j][k];
if(i==bag.size() - 1) {return d[i][j][k] =0;}
int now = j - ADD;
int ans1 = dp(i+1,ADD+(now-bag[i+1]),0) + bag[i+1];
int ans2 = dp(i+1,ADD+(now+bag[i+1]),1) - bag[i+1];
ans = abs(now - ans1) < abs(now - ans2) ? ans1 : ans2;
return ans;
}
vector<int> ans;
void print_ans(int i,int j,int k){
if(i == bag.size() - 1) return ;
if(d[i][j][k] == dp(i+1,ADD+(j-ADD-bag[i+1]),0) + bag[i+1]){
for(int g=0;g<st[i+1][0].size();g++)
ans.push_back(st[i+1][0][g]);
print_ans(i+1,ADD+(j-ADD-bag[i+1]),0);
}
else {
for(int g=0;g<st[i+1][1].size();g++)
ans.push_back(st[i+1][1][g]);
print_ans(i+1,ADD+(j-ADD+bag[i+1]),1);
}
}
int main(){
//freopen("input.txt","r",stdin);
int T,kase=0;
scanf("%d",&T);
while(T--){
if(kase++) printf("\n");
scanf("%d",&n);
for(int i=1;i<=n;i++) son[i].clear();
for(int i=1;i<=n;i++){
int x;
while(scanf("%d",&x)&&x){
son[i].push_back(x);
}
}
memset(G,false,sizeof(G));
for(int i=1;i<=n;i++){
memset(vis,false,sizeof(vis));
for(int j=0;j<son[i].size();j++) vis[son[i][j]] = true;
for(int j=1;j<=n;j++)if(j!=i){
if(!vis[j]){
G[i][j] = G[j][i] = true;
}
}
}
memset(color,0,sizeof(color));
bool flag=true;
bag.clear(); bag.push_back(0);
for(int i=1;i<=n;i++){
if(!color[i]){
int cnt = bag.size();
st[cnt][0].clear();
st[cnt][1].clear();
color[i] = 1; st[cnt][0].push_back(i);
if(!bipartite(i,cnt)){
flag=false; break;
}
int c1=st[cnt][0].size();
int c2=st[cnt][1].size();
bag.push_back(c1 - c2);
}
}
if(!flag){
printf("No solution\n"); continue;
}
memset(VIS,false,sizeof(VIS));
dp(0,ADD,0);
ans.clear(); print_ans(0,ADD,0);
memset(vis,false,sizeof(vis));
printf("%d",ans.size());
for(int i=0;i<ans.size();i++) {printf(" %d",ans[i]); vis[ans[i]]=1;}
printf("\n");
printf("%d",n-ans.size());
for(int i=1;i<=n;i++) if(!vis[i]) printf(" %d",i);
printf("\n");
}
return 0;
}
/*
2
5
3 4 5 0
1 3 5 0
2 1 4 5 0
2 3 5 0
1 2 3 4 0
5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0
*/