//题目大意:给定一个有向图,表示N个人之间的认识关系.现在需要把N个人分成两个team.
//要求每个team中的人必须互相认识.同时要求两个team的人数相差最少.
//题目连接:http://poj.org/problem?id=1112
//解题思路:把现有的建立的有向图求其补图.同时将有向边变成无向边.那么新构成的图G';
//G'的意义是:a-b有边表示a和b不能在一个team里面
//接下来对G'的每个连通分量进行2分染色.同时记录下每个分量染色为0和染色为1的数目.
//no solution的情况就是染色不成功.即出现一个点既不能是染色0.也不能是染色1;
//最后就是用dp处理两个team人数相差最少.
//dp[i][j]表示到第i个连通分量能否得到含有j个人数的team
//要求每个team中的人必须互相认识.同时要求两个team的人数相差最少.
//题目连接:http://poj.org/problem?id=1112
//解题思路:把现有的建立的有向图求其补图.同时将有向边变成无向边.那么新构成的图G';
//G'的意义是:a-b有边表示a和b不能在一个team里面
//接下来对G'的每个连通分量进行2分染色.同时记录下每个分量染色为0和染色为1的数目.
//no solution的情况就是染色不成功.即出现一个点既不能是染色0.也不能是染色1;
//最后就是用dp处理两个team人数相差最少.
//dp[i][j]表示到第i个连通分量能否得到含有j个人数的team
//dp[i][j] = (dp[i-1][j - 第i个中染色为0的数目] || dp[i-1][j- 第i个中染色为1的数目])
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
using namespace std;
const int mn = 111;
int rank[mn],father[mn],rs[mn],connum[mn][5],n,map[mn][mn],dp[mn][mn],cas[mn][mn];
int ans[mn][mn],ps[mn][mn];
vector<int>conne[mn];
void init(int x)
{
for(int i = 1 ; i <= x ; i++)
{
rank[i] = 0;
father[i] = i;
}
}
int find(int x)
{
if(x != father[x])
father[x] = find(father[x]);
return father[x];
}
void Union(int x , int y)
{
x = find(x);
y = find(y);
if(x == y)return ;
else
{
if(rank[x] < rank[y])father[x] = y;
else
{
if(rank[x] == rank[y])rank[x]++;
father[y] = x;
}
}
}
bool DFS(int i , int x , int ys)
{
vector<int>::iterator it;
for(it = conne[i].begin() ; it < conne[i].end() ; it++)
{
if(map[x][*it])
{
if(rs[*it] == -1)
{
rs[*it] = 1 - ys;
if(!DFS(i, *it , rs[*it]))return 0;
}
else if(rs[*it] != 1 - ys)return 0;
}
}
// if(!ppm)return 0;
return 1;
}
int main()
{
while(scanf("%d",&n) != EOF)
{
for(int i = 1 ; i <= n ; i++)conne[i].clear();
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= n ; j++)
{
if(i == j)map[i][j] = 0;
else map[i][j] = 1;
}
int x;
memset(cas,0,sizeof(cas));
for(int i = 1 ; i <= n ; i++)
while(scanf("%d",&x) && x != 0)
{
cas[i][x] = 1;
}
for(int i = 1 ; i <= n ; i++)
{
for(int j = 1 ; j <= n ; j++)
{
if(i == j )continue;
if(cas[i][j] && cas[j][i])
{
map[i][j] = 0;
map[j][i] = 0;
}
}
}
init(n);
for(int i = 1 ; i <= n ; i++)rs[i] = -1;
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= n ; j++)
if(map[i][j])Union(i,j);
int t = 1;
for(int i = 1 ; i <= n ; i++)
{
bool vis = 1;
int p ;
for(int j = 1 ; j < t ; j++)
if(find(i) == find( *(conne[j].begin()) ))
{
vis = 0;
p = j;
}
if(!vis)conne[p].push_back(i);
else conne[t++].push_back(i);
}
bool pp = 1;
memset(rs,-1,sizeof(rs));
for(int i = 1 ; i < t ; i++)
{
rs[*(conne[i].begin())] = 0;
if(!DFS( i,*(conne[i].begin()) , 0) )pp = 0;
}
if(!pp)printf("No solution\n");
else
{
for(int i = 1 ; i <= n ; i++)if(rs[i] == -1)while(1);
memset(connum,0,sizeof(connum));
for(int i = 1 ; i < t ; i++)
{
vector<int>::iterator it;
for(it = conne[i].begin() ; it < conne[i].end() ; it++)
connum[i][rs[*it]]++;
}
memset(dp,0,sizeof(dp));
dp[1][connum[1][0]] = 1;
ans[1][connum[1][0]] = 0;
dp[1][connum[1][1]] = 1;
ans[1][connum[1][1]] = 1;
for(int i = 2 ; i < t ; i++)
{
for(int j = 1 ; j <= n ; j++)
{
if(j >= connum[i][0] && dp[i-1][j - connum[i][0]])
{
dp[i][j] = 1;
ans[i][j] = 0;
}
if(j >= connum[i][1] && dp[i-1][j - connum[i][1]])
{
dp[i][j] = 1;
ans[i][j] = 1;
}
}
}
int res = 0;
for(int i = 1 ; i*2 <= n ; i++)
if(dp[t-1][i] && abs(i - n/2) < abs( res - n /2))
res = i;
bool flag = 1;
int mm = 1;
int tt = 1;
t--;
while(flag)
{
vector<int>::iterator it;
if(ans[t][res])
for(it = conne[t].begin() ; it < conne[t].end() ; it++)
{
if(rs[*it]) {res--;ps[1][mm++] = *it;}
else ps[2][tt++] = *it;
}
else
{
for(it = conne[t].begin() ; it < conne[t].end() ; it++)
if(rs[*it])ps[2][tt++] = *it;
else {res--;ps[1][mm++] = *it;}
}
t--;
if(!t)flag = 0;
}
// printf("%d\n",res);
printf("%d ",tt-1);
for(int i = 1 ; i < tt-1 ; i++)printf("%d ",ps[2][i]);
printf("%d\n",ps[2][tt-1]);
printf("%d ",mm-1);
for(int i = 1 ; i < mm-1 ; i++)printf("%d ",ps[1][i]);
printf("%d\n",ps[1][mm-1]);
}
}
}