Prince and Princess HDU - 4685

题面

传送门

前置

这道题我感觉是这道题换过来的, 先写写这道题

题解

这道题比 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 << ":\n";
        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 << '\n';
        }
    }
    return 0;
}
posted @ 2020-12-10 12:12  洛绫璃  阅读(84)  评论(0编辑  收藏  举报