【連通圖|二分匹配+強連通分量】POJ-1904 King's Quest

King’s Quest
Time Limit: 15000MS Memory Limit: 65536K
Case Time Limit: 2000MS

Description
Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those girls he did like. The sons of the king were young and light-headed, so it was possible for one son to like several girls.

So the king asked his wizard to find for each of his sons the girl he liked, so that he could marry her. And the king’s wizard did it – for each son the girl that he could marry was chosen, so that he liked this girl and, of course, each beautiful girl had to marry only one of the king’s sons.

However, the king looked at the list and said: “I like the list you have made, but I am not completely satisfied. For each son I would like to know all the girls that he can marry. Of course, after he marries any of those girls, for each other son you must still be able to choose the girl he likes to marry.”

The problem the king wanted the wizard to solve had become too hard for him. You must save wizard’s head by solving this problem.

Input
The first line of the input contains N – the number of king’s sons (1 <= N <= 2000). Next N lines for each of king’s sons contain the list of the girls he likes: first Ki – the number of those girls, and then Ki different integer numbers, ranging from 1 to N denoting the girls. The sum of all Ki does not exceed 200000.

The last line of the case contains the original list the wizard had made – N different integer numbers: for each son the number of the girl he would marry in compliance with this list. It is guaranteed that the list is correct, that is, each son likes the girl he must marry according to this list.

Output
Output N lines.For each king’s son first print Li – the number of different girls he likes and can marry so that after his marriage it is possible to marry each of the other king’s sons. After that print Li different integer numbers denoting those girls, in ascending order.

Sample Input

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

Sample Output

2 1 2
2 1 2
1 3
1 4

Hint
This problem has huge input and output data,use scanf() and printf() instead of cin and cout to read data to avoid time limit exceed.

Source
Northeastern Europe 2003


題意: 給出一個二分圖以及其中一個完備匹配,求對於每個X點,所有可以與之匹配的Y點,使得最終仍然能得到一個完備匹配。
思路:
你可以參考這兒:Polla 分析的很不錯。
剛看到這題會往二分圖匹配上想(雖然我直接就去看什麼是穩定婚姻問題了,但是該題和穩定婚姻沒有什麼關係)。如果忽略給出的那個完備匹配的話,可以枚舉所有的Y點與X匹配,之後進行二分匹配的判定。但是複雜度太高,勢必TLE。
給出的完備匹配一定包含了一些有用信息。既然X的信息全部在輸入數據中給出了,那麼完備匹配一定包含了一些關於Y的信息。有些X點是絕對不能和Y點在一起的,例如樣例中3號王子和2號女孩一定不能在一起,因爲這樣的話,1號王子和2號王子勢必有一個人單身。那麼完備匹配給出的信息就是“每個Y點可以喜歡的X點”。雖然沒有給全,但是一個足矣。
X點向喜歡的Y點連有向邊,再將給出的完備匹配中的Y點向X點也連上有向邊。假定給出的完備匹配是所有的Xi和Yi匹配,那麼假如Xi和Yj匹配,Yi和Xj勢必尋找另外的伴侶,設想Xi和Yj處於同一個強連通分量當中,強連通分量一定包含一個環,那麼Xj和Yi一定是能找到另外的伴侶的。
那麼是不是說,只要給出一組完備匹配,其他所有的完備匹配的方案都和它處於同一個強連通分量當中呢?
我覺得這樣說應該是沒有錯的。所有完備匹配方案之間應該是有一些共同的信息的。那就是一定成環。
P.S. 如果採用輸出輸出外掛,G++評測可以500+ms。但是IO外掛對於C++評測是無效的。
代碼如下:

/*
 * ID: j.sure.1
 * PROG:
 * LANG: C++
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <climits>
#include <iostream>
#define PB push_back
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
/****************************************/
const int N = 4444, M = 222222;
int n, tot, scc_cnt, deep;
int head[N], dfn[N], scc_id[N];
struct Edge {
    int v, next;
    Edge(){}
    Edge(int _v, int _next):
        v(_v), next(_next){}
}e[M];
stack <int> s;
vector<int> ans;

void init()
{
    tot = deep = scc_cnt = 0;
    memset(head, -1, sizeof(head));
    memset(dfn, 0, sizeof(dfn));
    memset(scc_id, 0, sizeof(scc_id));
}

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

int dfs(int u)
{
    int lowu = dfn[u] = ++deep;
    s.push(u);
    for(int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].v;
        if(!dfn[v]) {
            int lowv = dfs(v);
            lowu = min(lowu, lowv);
        }
        else if(!scc_id[v]) {
            lowu = min(lowu, dfn[v]);
        }
    }
    if(lowu == dfn[u]) {
        scc_cnt++;
        while(1) {
            int x= s.top(); s.pop();
            scc_id[x] = scc_cnt;
            if(x == u) break;
        }
    }
    return lowu;
}

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

int main()
{
#ifdef J_Sure
    freopen("000.in", "r", stdin);
    //freopen("999.out", "w", stdout);
#endif
    while(~scanf("%d", &n)) {
        int m, j;
        init();
        for(int i = 1; i <= n; i++) {
            scanf("%d", &m);
            while(m--) {
                scanf("%d", &j);
                add(i, j+n);
            }
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &j);
            add(j+n, i);
        }
        tarjan();
        for(int u = 1; u <= n; u++) {
            ans.clear();
            for(int i = head[u]; ~i; i = e[i].next) {
                int v = e[i].v;
                if(scc_id[u] == scc_id[v]) ans.PB(v-n);
            }
            size_t len = ans.size();
            printf("%d", (int)len);
            sort(ans.begin(), ans.end());
            for(size_t k = 0; k < len; k++) {
                printf(" %d", ans[k]);
            }
            puts("");
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章