思路:
首先,正着解有点难,我们反过来,如果两个人不认识,说明一定不能在同一个队伍里,我们给两个点连一条边,然后处于一个点双的点是确定一个其他都确定的,我们用染色法判断是否能染成二分图即可.染完色以后,我们看到差值最小,可以用背包解决.
记录这道题是因为这里的背包回溯的写法.
代码:
#include <bits/stdc++.h>
// #define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define ll long long
#define double long double
#define ull unsigned long long
#define PII pair<int, int>
#define PDI pair<double, int>
#define PDD pair<double, double>
#define debug(a) cout << #a << " = " << a << endl
#define point(n) cout << fixed << setprecision(n)
#define all(x) (x).begin(), (x).end()
#define mem(x, y) memset((x), (y), sizeof(x))
#define lbt(x) (x & (-x))
#define SZ(x) ((x).size())
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
namespace nqio{const unsigned R = 4e5, W = 4e5; char *a, *b, i[R], o[W], *c = o, *d = o + W, h[40], *p = h, y; bool s; struct q{void r(char &x){x = a == b && (b = (a = i) + fread(i, 1, R, stdin), a == b) ? -1 : *a++;} void f(){fwrite(o, 1, c - o, stdout); c = o;} ~q(){f();}void w(char x){*c = x;if (++c == d) f();} q &operator >>(char &x){do r(x);while (x <= 32); return *this;} q &operator >>(char *x){do r(*x); while (*x <= 32); while (*x > 32) r(*++x); *x = 0; return *this;} template<typename t> q&operator>>(t &x){for (r(y),s = 0; !isdigit(y); r(y)) s |= y == 45;if (s) for (x = 0; isdigit(y); r(y)) x = x * 10 - (y ^ 48); else for (x = 0; isdigit(y); r(y)) x = x * 10 + (y ^ 48); return *this;} q &operator <<(char x){w(x);return *this;}q &operator<< (char *x){while (*x) w(*x++); return *this;}q &operator <<(const char *x){while (*x) w(*x++); return *this;}template<typename t> q &operator<< (t x) {if (!x) w(48); else if (x < 0) for (w(45); x; x /= 10) *p++ = 48 | -(x % 10); else for (; x; x /= 10) *p++ = 48 | x % 10; while (p != h) w(*--p);return *this;}}qio; }using nqio::qio;
using namespace std;
const int N = 1e3 + 10, M = 2e6 + 10;
int n;
int h[M], v[M], to[M], tot, color[M], bl[M], cnt, a[M][2], f[N][N], ans[M], len;
int choose[N][N], pre[N][N];
void add(int a, int b) {
v[++tot] = b, to[tot] = h[a], h[a] = tot;
}
bool dfs(int x, int clr) {
bl[x] = cnt, color[x] = clr;
for (int i = h[x], y; i; i = to[i])
if ((color[y = v[i]] == -1 && !dfs(y, !clr)) || (color[y] == clr)) return false;
return true;
}
signed main() {
qio >> n;
for (int i = 1; i <= n; ++i) {
color[i] = -1;
int x; unordered_map<int, int> mp;
while (qio >> x, x) mp[x] = 1;
for (int j = 1; j <= n; ++j) if (!mp[j] && i != j) add(i, j), add(j, i);
}
for (int i = 1; i <= n; ++i)
if (color[i] == -1 && (++cnt, !dfs(i, 1))) return qio << "No solution\n", 0;
for (int i = 1; i <= n; ++i) ++a[bl[i]][color[i]];
f[0][n] = 1;
for (int i = 1; i <= cnt; ++i) {
int gap = a[i][0] - a[i][1];
for (int j = -n; j <= n; ++j)
if (f[i - 1][j + n]) {
if (j + gap <= n && j + gap >= -n) f[i][j + gap + n] = 1, pre[i][j + gap + n] = j + n, choose[i][j + gap + n] = 0;
if (j - gap <= n && j - gap >= -n) f[i][j - gap + n] = 1, pre[i][j - gap + n] = j + n, choose[i][j - gap + n] = 1;
}
}
int pos = 0, st;
while (pos <= n) {
if (f[cnt][n + pos] || f[cnt][n - pos]) break;
++pos;
}
if (f[cnt][n + pos]) /*0的人数大于1的人数*/ st = n + pos, qio << (pos + n) / 2 << " ";
else /*1的人数大于0的人数*/ st = n - pos, qio << (n - pos) / 2 << " ";
int i = cnt, j = st;
while (i) {
for (int kk = 1; kk <= n; ++kk) if (choose[i][j] == color[kk] && bl[kk] == i) ans[++len] = kk;
j = pre[i--][j];
}
sort(ans + 1, ans + 1 + len);
unordered_map<int, int> ok;
for (int i = 1; i <= len; ++i) qio << ans[i] << " ", ok[ans[i]] = 1;
qio << "\n";
qio << n - len << " ";
for (int i = 1; i <= n; ++i) if (!ok[i]) qio << i << " ";
qio << "\n";
}