hdu4685 Prince and Princess

题目描述

There are n princes and m princesses. Princess can marry any prince. But prince can only marry the princess they DO love.

For all princes,give all the princesses that they love. So, there is a maximum number of pairs of prince and princess that can marry.

Now for each prince, your task is to output all the princesses he can marry. Of course if a prince wants to marry one of those princesses,the maximum number of marriage pairs of the rest princes and princesses cannot change.

输入格式

The first line of the input contains an integer T(T<=25) which means the number of test cases.

For each test case, the first line contains two integers n and m (1<=n,m<=500), means the number of prince and princess.

Then n lines for each prince contain the list of the princess he loves. Each line starts with a integer ki(0<=ki<=m), and then ki different integers, ranging from 1 to m denoting the princesses.

输出格式

For each test case, first output "Case #x:" in a line, where x indicates the case number between 1 and T.

Then output n lines. For each prince, first print li, the number of different princess he can marry so that the rest princes and princesses can still get the maximum marriage number.

After that print li different integers denoting those princesses,in ascending order.

样例输入

2
4 4
2 1 2
2 1 2
2 2 3
2 3 4
1 2
2 1 2

样例输出

Case #1:
2 1 2
2 1 2
1 3
1 4
Case #2:
2 1 2

分析

题目大意:求二分图的所有可行边,即可能在最大匹配中的边。

先随便求一个最大匹配,则匹配边一定是可行边。

考虑判断非匹配边$(u,v)$是否是可行边,只需判断是否存在经过$(u,v)$的偶交替环。如果存在,取反即为包含$(u,v)$的最大匹配,则$(u,v)$是可行边。

判断方法:把匹配边从左到右连,把未匹配边从右到左连,做Tarjan缩点,然后判断$u,v$是否在同一个强连通分量中。

复杂度即为求二分图最大匹配的复杂度。

拓展:如何求二分图的关键边(必定在最大匹配中的边)?

同样随便求一个最大匹配,则未匹配边一定不是关键边。

考虑判断匹配边$(u,v)$是否不是关键边,只需判断是否存在经过$(u,v)$的偶交替环。如果存在,取反即为不包含$(u,v)$的最大匹配,则$(u,v)$不是关键边。

偶交替环求法同上。

代码

#include <bits/stdc++.h>

const int N = 2050;

int n, m;
bool mp[N][N];

namespace BG {
    int n, m;
    int lx[N], ly[N];
    bool vis[N];

    bool dfs(int u) {
        for (int v = 1; v <= m; v++) {
            if (mp[u][v] && !vis[v]) {
                vis[v] = true;
                if (!lx[v] || dfs(lx[v])) {
                    lx[v] = u;
                    ly[u] = v;
                    return true;
                }
            }
        }
        return false;
    }

    int hungary(int _n, int _m) {
        n = _n; m = _m;
        memset(lx, 0, sizeof lx);
        memset(ly, 0, sizeof ly);
        int rtn = 0;
        for (int i = 1; i <= n; i++) {
            memset(vis, 0, sizeof vis);
            rtn += dfs(i);
        }
        return rtn;
    }
}

namespace Tj {
    const int M = N * N;

    struct Graph {
        struct Edge {
            int to, nxt;
        } e[M];
        int top, head[N];

        Graph() {
            clear();
        }

        void clear() {
            top = 0;
            memset(head, -1, sizeof head);
        }

        void add(int u, int v) {
            e[top] = (Edge){v, head[u]};
            head[u] = top++;
        }
    } G;

    int dfx, dfn[N], low[N];
    int bcnt, bl[N];
    std::stack<int> stk;

    void add(int u, int v) {
        G.add(u, v);
    }

    void clear() {
        G.clear();
        dfx = bcnt = 0;
        memset(dfn, 0, sizeof dfn);
        memset(low, 0, sizeof low);
        memset(bl, 0, sizeof bl);
    }

    void dfs(int u) {
        low[u] = dfn[u] = ++dfx;
        stk.push(u);
        for (int i = G.head[u]; ~i; i = G.e[i].nxt) {
            int v = G.e[i].to;
            if (!dfn[v]) {
                dfs(v);
                low[u] = std::min(low[u], low[v]);
            } else if (!bl[v]) {
                low[u] = std::min(low[u], dfn[v]);
            }
        }
        if (low[u] == dfn[u]) {
            bcnt++;
            while (!stk.empty()) {
                int x = stk.top();
                stk.pop();
                bl[x] = bcnt;
                if (x == u) break;
            }
        }
    }

    void tarjan(int n) {
        for (int i = 1; i <= n; i++)
            if (!dfn[i]) dfs(i);
    }
}

void work() {
    scanf("%d%d", &n, &m);
    memset(mp, 0, sizeof mp);
    for (int u = 1; u <= n; u++) {
        int cnt, v;
        scanf("%d", &cnt);
        while (cnt--) {
            scanf("%d", &v);
            mp[u][v] = true;
        }
    }

    int res = BG::hungary(n, m);
    int nn = n + m - res;
    for (int i = n+1; i <= nn; i++)
        for (int j = 1; j <= m; j++)
            mp[i][j] = true;
    for (int j = m+1; j <= nn; j++)
        for (int i = 1; i <= n; i++)
            mp[i][j] = true;
    BG::hungary(nn, nn);

    Tj::clear();
    for (int i = 1; i <= nn; i++) {
        for (int j = 1; j <= nn; j++) {
            if (mp[i][j]) {
                if (j != BG::ly[i])
                    Tj::add(nn+j, i);
                else
                    Tj::add(i, nn+j);
            }
        }
    }       
    Tj::tarjan(nn*2);

    std::vector<int> ans;
    for (int u = 1; u <= n; u++) {
        ans.clear();
        for (int v = 1; v <= m; v++)
            if (BG::ly[u] == v || (mp[u][v] && Tj::bl[u] == Tj::bl[nn+v]))
                ans.push_back(v);
        int siz = ans.size();
        printf("%d", siz);
        for (int i = 0; i < siz; i++)
            printf(" %d", ans[i]);
        puts("");
    }
}

int main() {
    int T; scanf("%d", &T);
    for (int cas = 1; cas <= T; cas++) {
        printf("Case #%d:\n", cas);
        work();
    }
    return 0;
}


转载请注明出处。


评论列表,共 0 条评论

    暂无评论

发表评论