POJ1112 Team Them UP!
题面
你的任务是以下列方式将一些人分成两个小队:
1、每个人都属于其中一个团队;
2、每个团队至少有一名成员;
3、团队中的每个人都认识团队中的每个人;
4、团队的规模尽可能接近。
此任务可能有许多解决方案,你可以输出任何一种解决方案,或声明解决方案不存在。
输入格式
第一行包含整数N,表示共有N个人,他们被编号为1,2,…,N。
接下来N行,第 i 行包含多个用空格分隔开的整数,表示编号为i的人认识的人的编号列表,最后以0结尾。
注意A认识B不代表B一定认识A。
输出格式
如果不存在解决方案,则输出”No solution”。
如果存在,则输出两个队伍的成员信息,每个队伍占一行,首先输出队伍的人数,然后依次输出队伍成员的编号。
数据范围
2≤N≤100
输入样例:
5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0
输出样例:
3 1 3 5
2 2 4
题解
明显的建反边, 染色分组, 然后为了使得两队人数差最小, 用背包
但是! 我们可以贪心!
我们按照每次染色后的两组的差值排序, 从大到小, 贪心选就好了
小生bb, 都0202年了, poj还不支持c++11吗?
代码
int h[N][N], v[N];
vector<pair<VI, VI > > ans;
bool dfs(int x, int c) {
if (c == 1) v[x] = 1, ans.back().fi.pb(x);
else v[x] = 2, ans.back().se.pb(x);
rep (y, 1, n) {
if (!h[x][y] || v[y] == 3 - c) continue;
if (v[y] && v[y] == c) return 1;
if (dfs(y, 3 - c)) return 1;
}
return 0;
}
bool cmp(const pair<VI, VI> &a, const pair<VI, VI> &b) {
return abs((int)a.fi.size() - (int)a.se.size()) > abs((int)b.fi.size() - (int)b.se.size());
}
int main() {
IOS; cin >> n;
rep (i, 1, n) rep (j, i + 1, n) h[i][j] = h[j][i] = 1;
rep (i, 1, n) while (cin >> m, m) h[i][m] = 0;
rep (i, 1, n) rep (j, 1, n) if (h[i][j]) h[j][i] = 1;
rep (i, 1, n)
if (!v[i]) {
ans.pb({ VI(), VI() });
if (dfs(i, 1)) { cout << "No solution"; return 0;}
}
sort(all(ans), cmp);
VI &a = ans[0].fi, &b = ans[0].se;
for (int i = 1; i < ans.size(); ++i)
if (ans[i].fi.size() >= ans[i].se.size())
if (a.size() >= b.size()) a.insert(a.end(), all(ans[i].se)), b.insert(b.end(), all(ans[i].fi));
else b.insert(b.end(), all(ans[i].se)), a.insert(a.end(), all(ans[i].fi));
else
if (a.size() >= b.size()) b.insert(b.end(), all(ans[i].se)), a.insert(a.end(), all(ans[i].fi));
else a.insert(a.end(), all(ans[i].se)), b.insert(b.end(), all(ans[i].fi));
sort(all(a)); sort(all(b));
cout << a.size(); rep (i, 0, a.size() - 1) cout << ' ' << a[i];
cout << '\n' << b.size(); rep (i, 0, b.size() - 1) cout << ' ' << b[i];
return 0;
}