题面
前置
题解
这道题比 POI1904 难在什么地方呢?
首先没给预先的匹配关系, 那我们先跑一边最大匹配好了, 然后再按照 POI1904 写
然而注意到, POI1904 是 n 个 王子 n 个公主, 这道题是 n 个王子和 m 个公主
且存在某个王子娶不到公主, 某个公主也嫁不出去
那咋办么?
那就认为构造成 POI1904 的情况
对所有没匹配上的王子, 添加一个虚拟的公主, 直接让二者匹配, 且其他王子也要喜欢这个虚拟公主(天下谁人不喜欢虚拟人呢?)
对所有没匹配的上的公主, 添加一个虚拟的王子, 且这个虚拟王子喜欢所有的公主(恋与制作人喜欢所有的玩家)
这样会出现什么情况呢? 王子,虚拟王子和公主,虚拟公主 都有可以匹配上的对象, 且每个人都可以至少和一个同性挖墙脚
就和 POI1904 一样了, 直接有向图强连通缩点就行了, 至于为啥可以请移步
代码
int n, m, _, k;
vector<VI> h;
int c[N << 2], scnt, st[N << 2], top;
int dfn[N << 2], df, low[N << 2];
bool inst[N << 2];
void tarjan(int x) {
dfn[x] = low[x] = ++df, inst[st[++top] = x] = 1;
for (auto &y : h[x]) {
if (!dfn[y]) { tarjan(y); umin(low[x], low[y]); }
else if (inst[y]) umin(low[x], dfn[y]);
}
if (low[x] == dfn[x]) {
++scnt; int y;
do { inst[y = st[top--]] = 0; c[y] = scnt; } while (x != y);
}
}
VI match;
vector<bool> v;
bool dfs(int x) {
for (auto &y : h[x]) {
if (v[y - n]) continue; v[y - n] = 1;
if (!match[y - n] || dfs(match[y - n])) return match[y - n] = x, 1;
}
return 0;
}
int main() {
IOS; int cas = 0;
for (cin >> _; _; --_) {
cin >> n >> m; vector<VI>(n + m + 1).swap(h); VI(m + 1).swap(match);
cout << "Case #" << ++cas << ":
";
rep (i, 1, n) for (cin >> k; k; --k) { int v; cin >> v; h[i].pb(v + n); }
vector<bool> boy(n + 1);
rep (i, 1, n) { vector<bool>(m + 1).swap(v); boy[i] = dfs(i); }
rep (i, 1, m) if (match[i]) h[i + n].pb(match[i]);
rep (i, 1, n) if (!boy[i]) {
h.pb(VI(1, i)); h.back().pb(i);
rep (j, 1, n) h[j].pb(h.size() - 1);
}
rep (i, 1, m) if (!match[i]) {
h.pb(VI()); h[i + n].pb(h.size() - 1);
rep (j, 1, m) h.back().pb(j + n);
}
memset(dfn, 0, sizeof dfn); df = scnt = 0;
rep (i, 1, n + m) if (!dfn[i]) tarjan(i);
rep (i, 1, n) {
VI ans;
for (auto &y : h[i]) if (c[y] == c[i] && y - n <= m) ans.pb(y - n);
sort(all(ans)); cout << ans.size();
for (auto &y : ans) cout << ' ' << y; cout << '
';
}
}
return 0;
}