主要思路是大白书上的,利用二分图染色判断是不是no solution,二分图染色的那个函数就是judge和dfs,然后dp[i][j]==1表示把第i个二分图的一部分加入第一队后,第一队有j人,dp[i][j] == 0 表示把第i个联通块加入第一队后,第一队的人数不可能是j人,显然,设有m个联通块,n个人,那么如果有最优解,最优解就是dp[m][j]中j最接近n/2的。way[][]数组用来保存第一队的路径。
状态转移方程:
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
if(dp[i-1][j]) dp[i][j+team[i][0].size()] = dp[i][j+tem[i][1].size()] = 1.
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
vector<int> G[10000];
int rel[5000][5000];
int col[10000];
int diff[1000];
int dp[5000][5000];
int way[5000][5000];
int way2[5000][5000];
vector<int> team[10000][2];
int k = 1;
int n;
void print(int p)
{
int u = k-1;
printf("%d",p);
int aim = p;
while(aim)
{
int t = way[u][aim];
for(int i = 0; i < team[u][t].size(); i++)
printf(" %d",team[u][t][i]);
aim -= team[u][t].size();
u--;
}
printf("\n");
printf("%d",n-p);
aim = n-p;
u = k-1;
while(aim)
{
int t = !way[u][p];
for(int i = 0; i < team[u][t].size(); i++)
printf(" %d",team[u][t][i]);
aim -= team[u][t].size();
p -= team[u][!t].size();
u--;
}
printf("\n");
}
bool dfs(int i, int color)
{
col[i] = color;
team[k][color].push_back(i);
for(int j = 1; j <= n; j++)
{
if(i != j && !(rel[i][j] && rel[j][i]))
{
if(col[j] >= 0 && col[i] == col[j]) return false;
if(col[j] == -1 && !dfs(j, !color)) return false;
}
}
return true;
}
bool judge()
{
for(int i = 1; i <= n; i++)
{
if(col[i] == -1){
team[k][0].clear();
team[k][1].clear();
if(!dfs(i, 0)) return false;
k++;
}
}
return true;
}
void dynamic()
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i < k; i++)
{
for(int j = 0; j <= n; j++)
if(dp[i-1][j])
{
if(dp[i][j + team[i][0].size()] == 0){
dp[i][j + team[i][0].size()] = 1;
way[i][j + team[i][0].size()] = 0;
}
if(dp[i][j + team[i][1].size()] == 0){
dp[i][j + team[i][1].size()] = 1;
way[i][j + team[i][1].size()] = 1;
}
}
}
int p = 0;
int m = n/2;
while(1)
{
if(dp[k-1][m+p] == 1)
{
print(m+p);
break;
}
else
if(dp[k-1][m-p] == 1)
{
print(m-p);
break;
}
p++;
}
}
int main()
{
//freopen("ztest.txt","r",stdin);
//freopen("zans.txt","w",stdout);
int t;
int temp;
scanf("%d",&t);
int h = 1;
while(t--)
{
if(h)
h = 0;
else
printf("\n");
scanf("t= %d\n",t);
k = 1;
memset(rel, 0, sizeof(rel));
memset(col, -1, sizeof(col));
memset(diff, 0, sizeof(diff));
memset(way, -1, sizeof(way));
memset(way2, -1, sizeof(way2));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
G[i].clear();
for(int i = 1; i <= n; i++)
while(scanf("%d",&temp) && temp)
rel[i][temp] = 1;
for(int i = 1; i < n; i++)
for(int j = i + 1; j <= n; j++)
if(!(rel[i][j] && rel[j][i]))
{
G[i].push_back(j);
G[j].push_back(i);
}
if(!judge())
printf("No solution\n");
else
dynamic();
}
return 0;
}