poj 1904 King's Quest(强连通)

来源:互联网 发布:哪有好的java培训 编辑:程序博客网 时间:2024/05/19 02:42
King's Quest
Time Limit: 15000MS Memory Limit: 65536KTotal Submissions: 6358 Accepted: 2225Case 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

42 1 22 1 22 2 32 3 41 2 3 4

Sample Output

2 1 22 1 21 31 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个王子,每个王子都喜欢若干个女人。给出每个王子喜欢的女人,并且给出一个方案,使每个王子都能和自己喜欢的女人结婚。现在要求列出每个王子所有的可以结婚的女人,并且每个王子选了一个女人结婚后,其他的王子都能结婚。
 
思路:利用二分图的增广路思想,设王子集合{x1,x2,......,xn},女人集合{y1,y2,......,yn},假设在原完美匹配方案中每个匹配都是(xi,yi),显然yi是xi的一个选项。假如xi选了yj(j!=i),则原先与yj匹配的王子xj要找另一个女人,yi要与另一个王子匹配,假如xj喜欢yi,那么yj就可以是xi的另一个选项了,假如xj不喜欢yi,那么就继续下去拆散现有的完美匹配,直到有个王子喜欢yi。所以这样就相当于要找一条由xi出发到yi的通路(等价于由xi出发回到xi的回路),只要这样的回路存在,王子就可以与回路中任意一个他喜欢的女人匹配了。这样也就相当于求包含xi的强连通分量。(注意:求出强连通分量之后,只有王子喜欢的女人才能匹配)。
 
具体做法:将每个王子与他喜欢的每个女人连一条有向边,然后在完美匹配中将每个女人和与她匹配的王子连一条有向边,然后缩点求强连通分量。
 
AC代码:
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <queue>#include <vector>#include <cmath>#include <stack>#include <cstdlib>using namespace std;const int maxm=1000000;const int maxn=4005;struct node{    int v,next;} edge[maxm];int G[maxn],RG[maxn],fin[maxn],scc[maxn],ans[maxn/2][maxn/2];int n,snum,num;bool vis[maxn];void init(){    memset(G,-1,sizeof(G));    memset(RG,-1,sizeof(RG));    num=0;}void add(int *head,int u,int v){    edge[num].v=v;    edge[num].next=head[u];    head[u]=num++;}void dfs1(int x){    vis[x]=true;    for(int i=G[x]; i!=-1; i=edge[i].next)        if(!vis[edge[i].v]) dfs1(edge[i].v);    fin[snum++]=x;}void dfs2(int x,int id){    vis[x]=true;    scc[x]=id;    for(int i=RG[x]; i!=-1; i=edge[i].next)        if(!vis[edge[i].v]) dfs2(edge[i].v,id);}void solve(){    memset(vis,false,sizeof(vis));    snum=1;    for(int i=1; i<=2*n; i++)        if(!vis[i]) dfs1(i);    memset(vis,false,sizeof(vis));    snum=1;    for(int i=2*n; i>=1; i--)        if(!vis[fin[i]])        {            dfs2(fin[i],snum);            snum++;        }    snum--;    for(int i=1; i<=n; i++)    {        int cnt=1;        for(int j=G[i]; j!=-1; j=edge[j].next)            if(scc[i]==scc[edge[j].v])                ans[i][cnt++]=edge[j].v-n;        sort(ans[i]+1,ans[i]+cnt);        ans[i][0]=cnt-1;    }    for(int i=1;i<=n;i++)    {        printf("%d ",ans[i][0]);        for(int j=1;j<ans[i][0];j++)        printf("%d ",ans[i][j]);        printf("%d\n",ans[i][ans[i][0]]);    }}int main(){    int v,k;    while(~scanf("%d",&n))    {        init();        for(int i=1; i<=n; i++)        {            scanf("%d",&k);            while(k--)            {                scanf("%d",&v);                add(G,i,v+n);                add(RG,v+n,i);            }        }        for(int i=1; i<=n; i++)        {            scanf("%d",&v);            add(G,v+n,i);            add(RG,i,v+n);        }        solve();    }    return 0;}

原创粉丝点击