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; }