码迷,mamicode.com
首页 > 其他好文 > 详细

POJ - 1904 King's Quest(强连通分量+二分图匹配)

时间:2015-08-16 00:40:02      阅读:147      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:有N个帅哥和N个美女,现在给出每个帅哥所喜欢的美女的编号,和一个帅哥和美女的完美匹配
问每个帅哥可以娶多少个美女,且当他娶完这个美女后,剩下的人还可以完美匹配

解题思路:神题啊,给一个大神的详细解答
具体是这样的,首先先建边,把帅哥和能娶到的美女连边,再把完美匹配的美女和帅哥连边,这样就形成了一张有向图了
接着,找出这张有向图的所有强连通分量,在强连通分量里面的帅哥都可以娶到自己喜欢的美女,且娶完这个美女后,不会影响到其他人
为什么呢?
假设xi为帅哥,yi和yj为美女,假设给定的完美匹配中xi和yi匹配。
现在,我们想让xi和yj匹配,按照二分图匹配,先要找到一条增广链
因为要完美匹配,所以这条增广链最后肯定会指向yi的,那如果把yi再连向xi,是不是就形成了一个环了,那这个环肯定是一个强连通分量了。
所以说,如果xi可以选择yj,那么xi和yj必定是在同一个连通分量里面了

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

#define N 4010
#define M 1000010
#define S 2010
#define min(a,b) ((a)<(b) ? (a) : (b))
#define max(a,b) ((a)>(b) ? (a) : (b))

struct Edge{
    int from, to, next;
}E[M];

int pre[N], sccno[N], stack[N], lowlink[N], head[N];
int n, m, dfs_clock, scc_cnt, top, tot;
int love[S][S];

void dfs(int u) {
    pre[u] = lowlink[u] = ++dfs_clock;
    stack[++top] = u;

    int v;
    for (int i = head[u]; i != -1; i = E[i].next) {
        v = E[i].to;
        if (!pre[v]) {
            dfs(v);
            lowlink[u] = min(lowlink[u], lowlink[v]);
        }
        else if (!sccno[v]) {
            lowlink[u] = min(lowlink[u], pre[v]);
        }
    }

    if (lowlink[u] == pre[u]) {
        scc_cnt++;
        while (1) {
            v = stack[top--];
            sccno[v] = scc_cnt;
            if (v == u)
                break;
        }
    }
}

vector<int> v[N];
void solve() {
    memset(pre, 0, sizeof(pre));
    memset(sccno, 0, sizeof(sccno));
    dfs_clock = scc_cnt = top = 0;

    for (int i = 0; i < 2 * n; i++)
        if (!pre[i])
            dfs(i);

    for (int i = 0; i < n; i++)
        v[i].clear();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (sccno[i] == sccno[j + n] && love[i][j]) 
                v[i].push_back(j +  1);
        }
        printf("%d", v[i].size());
        for (int j = 0; j < v[i].size(); j++)
            printf(" %d", v[i][j]);
        printf("\n");
    }
}

void AddEdge(int u, int v) {
    E[tot].from = u;
    E[tot].to  =v;
    E[tot].next = head[u];
    head[u] = tot++;
}

void init() {
    memset(head, -1, sizeof(head));
    memset(love, 0, sizeof(love));
    tot = 0;

    int t, u, v;
    for (u = 0; u < n; u++) {
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &v);
            love[u][v - 1] = true;
            AddEdge(u, v + n - 1);
        }
    }


    for (int i = 0; i < n; i++) {
        scanf("%d", &v);
        AddEdge(v - 1 + n, i);
    }
}

int main() {
    while (scanf("%d", &n) != EOF) {
        init();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ - 1904 King's Quest(强连通分量+二分图匹配)

标签:

原文地址:http://blog.csdn.net/l123012013048/article/details/47690005

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!