此题初看起来是一个二分匹配的问题,一个国王有n个儿子,将要与n个女孩结婚,已知每个儿子喜欢某几个女孩,并给出了一个初始匹配,问题是求每个儿子可能与哪些他喜欢的女孩结婚,一旦他选一个结婚后,其他的儿子仍能选到自己喜欢的人结婚。若直接枚举个中可能,然后用匈牙利算法求完美匹配判断,这样的话时间复杂度是O(n5),毫无疑问会超时。在这里,题目给出里一个初始完美匹配,必须加以利用。我们可以把初始完美匹配中的每一对看成结点进行构图,因此每个结点包含一个男孩和一个女孩,若结点i中的男孩喜欢结点j中的女孩,就在结点i与结点j之间连一条有向边,这样问题就转化为求强分图,每个男孩可以与他喜欢的并且与他在同一个强分图中的一个女孩结婚且不影响到其他人。求强分图,我用的是两次dfs的算法。
View Code
1 #include <stdio.h>
2 #include <string.h>
3 #define CLR(a) (memset(a,0,sizeof(a)))
4 #define N 2005
5 char vis[N],g[N][N];
6 int boy[N],girl[N],n;
7 int ord[N],id[N],cnt;
8 void dfs(int u)
9 {
10 int i,v;
11 vis[u]=1;
12 for(i=0;i<n;i++)
13 {
14 if(g[u][i])
15 {
16 v=boy[i];
17 if(!vis[v]) dfs(v);
18 }
19 }
20 ord[cnt++]=u;
21 }
22 void rdfs(int u)
23 {
24 int i=girl[u],v;
25 vis[u]=1,id[u]=cnt;
26 for(v=0;v<n;v++)
27 {
28 if(g[v][i]&&!vis[v]) rdfs(v);
29 }
30 }
31 void kosaraju()
32 {
33 int i,j,v,t,ans[N],num;
34 CLR(vis);
35 for(i=0,cnt=0;i<n;i++)
36 {
37 if(!vis[i]) dfs(i);
38 }
39 CLR(vis);
40 for(t=n-1,cnt=0;t>=0;t--)
41 {
42 i=ord[t];
43 if(!vis[i])
44 {
45 rdfs(i);
46 cnt++;
47 }
48 }
49 for(i=0;i<n;i++)
50 {
51 for(v=0,num=0;v<n;v++)
52 {
53 if(!g[i][v]) continue;
54 j=boy[v];
55 if(id[i]==id[j]) ans[num++]=v+1;
56 }
57 printf("%d",num);
58 for(j=0;j<num;j++) printf(" %d",ans[j]);
59 printf("\n");
60 }
61 }
62 int main()
63 {
64 int i,j,k;
65 while(scanf("%d",&n)!=EOF)
66 {
67 CLR(g);
68 for(i=0;i<n;i++)
69 {
70 scanf("%d",&k);
71 while(k--)
72 {
73 scanf("%d",&j);
74 g[i][j-1]=1;
75 }
76 }
77 for(i=0;i<n;i++)
78 {
79 scanf("%d",&j);
80 girl[i]=j-1;
81 boy[girl[i]]=i;
82 }
83 kosaraju();
84 }
85 return 0;
86 }