poj 1904 King's Quest 【建模 求解SCC】

King's Quest
Time Limit: 15000MS   Memory Limit: 65536K
Total Submissions: 8145   Accepted: 2955
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.


题意:有N个男孩和N个女孩。对每一个男孩,已经给出他所喜欢的女孩。现在给你一个满足完美匹配的婚配表,让你求出另一个表——在满足完美匹配的前提下,每个男孩可以与哪些女孩结婚。



把男孩i虚拟成节点i,女孩i虚拟成节i+N。我们用i - > i+N表示i喜欢i+N,用i+N->i表示 i与i+N结婚。

建图如下:

每个男孩向他喜欢的女孩建边,对于给出的完美匹配婚配表,每个女孩向她的男伴建边。

最后在图中跑一次tarjan。对男孩i所在的SCC,若有一个女孩节点j+N(j女孩)满足i -> j+N 则必然有i可以与j+N结婚。


AC代码:(注意要用数组标记男孩i和女孩j之间是否有边,若一个个查询会TLE)


#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define MAXN 5000
#define MAXM 20000000
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int low[MAXN], dfn[MAXN];
int sccno[MAXN], scc_cnt;
bool Instack[MAXN];
int dfs_clock;
stack<int> S;
vector<int> scc[MAXN];
int N;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v)
{
    Edge E1 = {u, v, head[u]};
    edge[edgenum] = E1;
    head[u] = edgenum++;
}
int Map[2001][2001];
void getMap()
{
    init();
    int a;
    int num;
    memset(Map, 0, sizeof(Map));
    for(int i = 1; i <= N; i++)
    {
        scanf("%d", &num);
        while(num--)
        {
            scanf("%d", &a);
            addEdge(i, a+N);
            Map[i][a] = 1;
        }
    }
    for(int i = 1; i <= N; i++)
    {
        scanf("%d", &a);
        addEdge(a+N, i);
    }
}
void tarjan(int u, int fa)
{
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    S.push(u);
    Instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(Instack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        scc_cnt++;
        scc[scc_cnt].clear();
        for(;;)
        {
            v = S.top();S.pop();
            sccno[v] = scc_cnt;
            Instack[v] = false;
            scc[scc_cnt].push_back(v);
            if(u == v) break;
        }
    }
}
void find_cut(int l, int r)
{
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(Instack, false, sizeof(Instack));
    memset(sccno, 0, sizeof(sccno));
    dfs_clock = scc_cnt = 0;
    for(int i = l; i <= r; i++)
        if(!dfn[i]) tarjan(i, -1);
}
int rec[MAXN];//记录可婚配的女孩编号
void solve()
{
    find_cut(1, 2*N);
    for(int i = 1; i <= N; i++)
    {
        int u = sccno[i];//男孩所在的SCC
        int sum = 0;//统计数目
        for(int j = 0; j < scc[u].size(); j++)
        {
            if(scc[u][j] > N && Map[i][scc[u][j]-N])//在一个强连通分量 且有边相连
                rec[sum++] = scc[u][j] - N;//记录编号
        }
        printf("%d", sum);
        sort(rec, rec+sum);
        for(int j = 0; j < sum; j++)
            printf(" %d", rec[j]);
        printf("\n");
    }
}
int main()
{
    while(scanf("%d", &N) != EOF)
    {
        getMap();
        solve();
    }
    return 0;
}


你可能感兴趣的:(poj 1904 King's Quest 【建模 求解SCC】)