状态是前i个能凑到的与j最相近的数。
/*test case
1
5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0
*/
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>
#define INF 100000000
using namespace std;
const int maxn = 100 + 5, mid = 103;
int head[maxn], V[maxn*maxn], skip[maxn*maxn], L, N;
bool G[maxn][maxn],mark[maxn][2*maxn];
int adjient[maxn], R, vis[maxn],d[maxn][2*maxn];
struct Nima {
int id, type;
Nima(int id, int type) : id(id), type(type) {}
};
vector<Nima> liantong[maxn];
// simple judge
bool pd(int J) {
if(J<2*maxn && J >= 0) return true;
return false;
}
bool opt(int j, int u, int o) {
j -= mid;
if(abs(o-j) < abs(u-j)) return true;
return false;
}
void init() {
memset(d, 0, sizeof(d));
memset(G, 0, sizeof(G));
L = -1;
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
for(int i = 0; i <= R; i++) liantong[i].clear();
R = 0;
}
bool dfs(int dot, int& num) {
num+=vis[dot];
liantong[R].push_back(Nima(dot, vis[dot]));
for(int u = head[dot]; u != -1; u = skip[u])
{
if(!vis[V[u]]) {
vis[V[u]] = -vis[dot];
if(!dfs(V[u], num)) return false;
}else if(vis[V[u]] == vis[dot]) return false;
}
return true;
}
int main() {
int k;
init();
scanf("%d",&N);
for(int i = 1; i <= N; i++) {
int x;
while(scanf("%d",&x)==1 && x) G[i][x] = 1;
}
for(int i = 1; i <= N; i++)
for(int j = i+1; j <= N; j++)
{
if(!G[i][j] || !G[j][i]) {
V[++L] = j; skip[L] = head[i]; head[i] = L;
V[++L] = i; skip[L] = head[j]; head[j] = L;
}
}
bool wrong = 0;
for(int i = 1; i <= N; i++) {
if(!vis[i]) {
++R;
vis[i] = 1;
k = 0;
if(!dfs(i,k)){wrong = 1; break;}
adjient[R] = k;
}
}
/*
//test
for(int i = 1; i <= R; i++) {
printf("liantong %d: ",i);
for(int j = 0; j < liantong[i].size(); j++) {
printf("%d ",liantong[i][j].id);
}
putchar('\n');
}
*/
if(wrong) {printf("No solution\n");return 0; }
//d[0][0~maxn*2-1] = 0;
for(int i = 1; i <= R; i++) {
for(int j = 0; j < 2*maxn; j++) {
d[i][j] = INF;
if(pd(j-adjient[i]) && opt(j, d[i][j], d[i-1][j-adjient[i]]+adjient[i]) ) {
d[i][j] = d[i-1][j-adjient[i]] + adjient[i];// we choose to add
mark[i][j] = 1;
}
if(pd(j+adjient[i]) && opt(j, d[i][j], d[i-1][j+adjient[i]]-adjient[i]) ) {
d[i][j] = d[i-1][j+adjient[i]]-adjient[i]; // we choose to reduce
mark[i][j] = 0;
}
}
}
vector<int> left, right; // 1 for left, -1 for right; when mark is 0, we turn around ;
for(int i = R, now = mid; i>=1; i--) {
if(mark[i][now]) {
for(int U = 0; U < liantong[i].size(); U++) {
Nima& K = liantong[i][U];
if(K.type == 1) left.push_back(K.id);
else right.push_back(K.id);
}
now -= adjient[i];
} else {
for(int U = 0; U < liantong[i].size(); U++) {
Nima& K = liantong[i][U];
if(K.type == -1) left.push_back(K.id);
else right.push_back(K.id);
}
now += adjient[i];
}
}
printf("%d",left.size()); sort(left.begin(), left.end());
for(vector<int>:: iterator tat = left.begin(); tat != left.end(); ++tat) {
printf(" %d",*tat);
}
printf("\n");
printf("%d",right.size()); sort(right.begin(), right.end());
for(vector<int>:: iterator tat = right.begin(); tat != right.end(); ++tat) {
printf(" %d",*tat);
}
printf("\n");
return 0;
}