您的位置:首页 > 产品设计 > UI/UE

POJ 1904 King's Quest强连通分量+二分图完美匹配

2016-05-10 11:11 405 查看

题目描述:

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个儿子,每个儿子都有Ki个喜欢的姑娘。媒婆(题目里是wizard-.-)给他的儿子都做了媒。(给他们都分配了一个他们喜欢的姑娘)。国王要求在每个儿子都能娶到自己喜欢的姑娘的前提下,每个儿子能够娶的姑娘编号。

我乍一看是一道二分图的题目,王子和姑娘配对。后面发现其实是一道求强连通分量的题目。将姑娘编号都加上n,王子对姑娘建边,按照媒婆的匹配姑娘和王子反向建边,然后寻找强连通分量,如果王子和另一个姑娘在同一个连通分量上,说明可以娶。因为同一个强连通分量种都有相同数量的姑娘和王子,王子在找别的姑娘的同时,他的原配姑娘也能被在同一个连通分量的另一个王子找到。(为什么听上去污污的0.0),所以这道题就是利用完美匹配去找强连通分量的题。

代码如下:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;

const int MAXN = 4010;
const int MAXM =200000+4000;
struct Edge
{
int to,next;
}edge[MAXM];
int head[MAXN],tot;
int low[MAXN],dfn[MAXN],stack[MAXN],belong[MAXN];
int index,top;
int scc;
bool instack[MAXN];
int n;
int ans[MAXN];

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

void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}

void Tarjan(int u)//求强连通分量
{
int v;
low[u]=dfn[u]=++index;
stack[top++]=u;
instack[u]=true;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
v=edge[i].to;
if (!dfn[v])
{
Tarjan(v);
if (low[u]>low[v]) low[u]=low[v];
}
else if (instack[v] && low[u]>dfn[v])
{
low[u]=dfn[v];
}
}
if (low[u]==dfn[u])
{
scc++;
do
{
v=stack[--top];
instack[v]=false;
belong[v]=scc;
}
while(v!=u);
}
}

void solve(int N)
{
memset(dfn,0,sizeof(dfn));
memset(instack,false,sizeof(instack));
index=scc=top=0;
for(int i=1; i<=N; i++)
{
if (!dfn[i])
Tarjan(i);
}
}

int main()
{
while(scanf("%d",&n)!=-1)
{
init();
for(int i=1; i<=n; i++)
{
int k;
scanf("%d",&k);
for(int j=1; j<=k; j++)
{
int v;
scanf("%d",&v);
addedge(i,v+n);
}
}
for(int i=1; i<=n; i++)
{
int v;
scanf("%d",&v);
addedge(v+n,i);
}
solve(2*n);
for(int u=1; u<=n; u++)
{
int count=0;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(belong[u]==belong[v])   //同一个强连通分量
ans[count++]=v-n;
}
sort(ans,ans+count);
printf("%d",count);
for(int i=0; i<count; i++)
{
printf(" %d",ans[i]);
}
printf("\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: