pku 1904
题目大意是有一个国王,他有n个儿子,现在有n个美丽的女子准备嫁给他的n个儿子。国王已经让他的大臣收集了每个儿子喜欢的姑娘的编号(可以喜欢很多个),并且大臣们已经找出了一个完美匹配的方案。现在国王不满意,他想要知道所有可能的匹配方案(前提是每个儿子可以娶到一个姑娘)。即求出每个儿子所有可能的结婚方案。
这题的解法是:
1、根据题目信息建图(王子->姑娘)。
2、根据题目给定的完美匹配建图(姑娘->王子)。
3、求强连通分量
4、如果某个姑娘和王子在一个连通分量,并且他们之间在原图上存在直接边,那么这个姑娘便是王子的可能匹配
分析:
根据题意,每个王子喜欢的姑娘已经确定了,他只能娶他喜欢的。既然是n个王子,n个姑娘。也就是说,最终最终还是一对一,即每个王子必须要有一个老婆。
假如某一个王子已经和一个姑娘完美匹配了,现在可能存在其他方案,假如这个方案中,王子a和王子b喜欢的某一个姑娘匹配,那么对于王子b来说,他就少了一个老婆的选择了,那怎么办呢?他就只能再去匹配上一个别的王子的姑娘。一次类推,那么这个王子怎么办呢?很有可能最后一个王子便没有老婆了。如果要避免最后一个王子没有老婆的情况发生,那么他就只能管第一个王子要了,谁让他抢走了别人的姑娘呢。这么一折腾,就形成了一个环,也就是一个强连通分量。也就是说,在一个强连通分量里,王子间是可以相互交换老婆的...那么为什么还要原图存在直接边呢?因为直接边说明王子喜欢这个女孩,如果他要了一个自己不喜欢的,那么别的王子自然会少掉一个喜欢的女孩。这是不道德的~
下面是代码:
#include<iostream>
#include<string>
#include<stack>
using namespace std;
typedef struct node
{
int v;
struct node *next;
}node;
node *link[5000];
node edge[400000];
int num,n;
void add(int u,int v)
{
edge[num].v=v;
edge[num].next=link[u];
link[u]=edge+num++;
}
int find(int u,int v)
{
for(node *p=link[u];p;p=p->next)
{
if(p->v==v)
return 1;
}
return -1;
}
int dnf[5000],low[5000],instack[5000],belong[5000];
int cut,mm;
stack<int>Q;
void tarjan(int u)
{
low[u]=dnf[u]=++mm;
instack[u]=1;
Q.push(u);
for(node *p=link[u];p;p=p->next)
{
if(!dnf[p->v])
{
tarjan(p->v);
if(low[u]>low[p->v])
{
low[u]=low[p->v];
}
}
else if(instack[p->v] && low[u]>dnf[p->v])
{
low[u]=dnf[p->v];
}
}
int v;
if(low[u]==dnf[u])
{
cut++;
do
{
v=Q.top();
Q.pop();
instack[v]=0;
belong[v]=cut;
}while(u!=v);
}
}
void solve()
{
cut=0;
mm=0;
memset(instack,0,sizeof(instack));
memset(dnf,0,sizeof(dnf));
for(int i=1;i<=2*n;i++)
{
if(!dnf[i])
tarjan(i);
}
}
int main()
{
int i,j,k,a;
freopen("D:\\in.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
memset(link,0,sizeof(link));
num=0;
for(i=1;i<=n;i++)
{
scanf("%d",&k);
for(j=1;j<=k;j++)
{
scanf("%d",&a);
add(i,a+n);
}
}
for(i=1;i<=n;i++)
{
scanf("%d",&a);
add(a+n,i);
}
solve();
int ans[2001];
for(i=1;i<=n;i++)
{
k=0;
for(j=n+1;j<=2*n;j++)
{
if(belong[i]==belong[j] && find(i,j)!=-1)
{
ans[k++]=j-n;
}
}
printf("%d",k);
for(j=0;j<k;j++)
{
printf(" %d",ans[j]);
}
printf("\n");
}
}
return 0;
}