King's Quest
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 |
题目大意:
国王有N个儿子,每个儿子都有几个喜欢的女孩(一共有N的女孩),现在已经知道一种可以让每一个王子都和其中一个自己喜欢的女孩结婚的方案,求每个王子能够结婚且不会导致其他王子无法结婚的女孩。
解题思路:
题目给的明显是一个二分图,首先很自然的就想到二分图匹配。这样我们就可以先想到一个朴素的算法:删除一个王子和一个他喜欢的女孩,然后对剩下的人进行二分图匹配,若匹配数是N-1则这一对满足要求,否则不满足。不过这样的复杂度是O(E*N^3),显然时间复杂度太高。
不过,我们还没有用上题目已给的一个完美匹配,而且我们也不需要求出具体的匹配,只需要判断一条边是否能在完美匹配中即可。还是从二分图匹配开始思考,假设开始ai与bi匹配,aj与匹配bj。如果我们想让与ai匹配bj,aj与匹配bi,那么就会产生这样一条增广路:bi->ai->bj->aj->bi,这时我们可以发现增广路形成了一个有向环,于是我们就可以按照刚才的增广方式建图:若ai喜欢bj则连接一条从ai到的bj边,若起始ai于bj匹配,则再连接一条从bj到ai的边。在这个图上,如果与在一个强连通分量上并且喜欢,就说明他们可以通过增广匹配到一起。所以我们只需要求强连通分量即可。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
const int MAXN=2000+3;
const int MAXV=MAXN*2;
int N,vis[MAXV],dfn[MAXV],low[MAXV],belong[MAXV],n_dfn,n_gruop;
vector<int> G[MAXV],save[MAXN];
stack<int> st;
bool G0[MAXN][MAXN];//原始的喜欢关系
void tarjan(int u)//tarjan算法求强连通分量
{
vis[u]=1;
dfn[u]=low[u]=++n_dfn;
st.push(u);
for(int i=0;i<G[u].size();++i)
{
int v=G[u][i];
if(!vis[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]==1)
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
++n_gruop;
while(true)
{
int v=st.top(); st.pop();
belong[v]=n_gruop;
if(v>N)
save[n_gruop].push_back(v-N);
vis[v]=2;
if(v==u)
break;
}
}
}
void init()//初始化
{
for(int i=1;i<=2*N;++i)
{
G[i].clear();
vis[i]=0;
}
for(int i=1;i<=N;++i)
{
save[i].clear();
for(int j=1;j<=N;++j)
G0[i][j]=false;
}
n_dfn=n_gruop=0;
}
int main()
{
while(~scanf("%d",&N))
{
init();
for(int u=1;u<=N;++u)
{
int num;
scanf("%d",&num);
for(int i=0;i<num;++i)
{
int v;
scanf("%d",&v);
G[u].push_back(v+N);
G0[u][v]=true;
}
}
for(int u=1;u<=N;++u)
{
int v;
scanf("%d",&v);
G[v+N].push_back(u);
}
for(int i=1;i<=N*2;++i)
if(!vis[i])
tarjan(i);
for(int i=1;i<=n_gruop;++i)
sort(save[i].begin(),save[i].end());
for(int i=1;i<=N;++i)
{
int g=belong[i],cnt=0;
for(int j=0;j<save[g].size();++j)
if(G0[i][save[g][j]])
++cnt;
printf("%d",cnt);
for(int j=0;j<save[g].size();++j)
if(G0[i][save[g][j]])
printf(" %d",save[g][j]);
putchar('\n');
}
}
return 0;
}