POJ 1904(强连通分量)Tarjan

题意描述:有n个王子和n个美女,每个王子有自己喜欢的美女,保证每个王子都能娶到一个自己喜欢的美女,现在巫师给出了一个王子和美女匹配的方案,但是国王想知道每个王子能够娶到的美女的名单(保证每个王子都能娶到美女)

 

思路:一看就是二分图,求所有可行的完全匹配的边集,但是想想二分图里面没有可以直接或者间接套用的算法。

不知道大家看到数据提供的一组匹配时是什么感想,应该要猜测到这组数据肯定有用。

那么假设现在我们按照数据提供的匹配已经匹配好了,这是对于u王子,如果他和v美女(非原配)匹配的话,到最后,则必然要有另一个王子和u的原配美女匹配

想想,发现这是一个环,想到强连通了么??

 

先别看以下的内容,先思考再看!

 

构图:每个王子向他喜欢的美女连一条有向边,对于数据中的匹配,每个美女向其匹配的王子连一条有向边,然后强连通就行了。

PS:注意在同一个强连通分量中的美女并不是都能和在该连通分量王子匹配(王子不一定喜欢她,为此狂WA,单恋就是不好。。。)

 

View Code
 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <iostream>
 5 #define N 5000
 6 #define M 700000 
 7 using namespace std;
 8 int n,t,divg,cnt,p,stack[N],head[N],to[M],next[M],dfn[N],low[N],belong[N],map[2001][2001];
 9 bool fg[N];
10 inline void add(int u,int v) 
11 {
12     to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++;
13 }
14 void read()
15 {
16     memset(fg,0,sizeof fg);
17     memset(head,-1,sizeof head); cnt=0;
18     memset(dfn,0,sizeof dfn);
19     memset(belong,0,sizeof belong);
20     memset(map,0,sizeof map);
21     t=0; divg=0; p=0;
22     for(int i=1,a,b;i<=n;i++)
23     {
24         scanf("%d",&a);
25         while(a--) scanf("%d",&b),add(i,n+b),map[i][b]=true;
26     }
27     for(int i=1,a;i<=n;i++) scanf("%d",&a),add(a+n,i);
28 }
29 void dfs(int u)
30 {
31     t++;
32     dfn[u]=low[u]=t;
33     stack[++p]=u; fg[u]=true;
34     for(int i=head[u];~i;i=next[i])
35     {
36         if(!dfn[to[i]])
37         {
38             dfs(to[i]);
39             low[u]=min(low[u],low[to[i]]);
40         }
41         else if(fg[to[i]]) low[u]=min(low[u],dfn[to[i]]);
42     }
43     if(dfn[u]==low[u])
44     {
45         divg++;
46         int tmp=-1;
47         while(tmp!=u)
48         {
49             tmp=stack[p--];
50             belong[tmp]=divg;
51             fg[tmp]=false;
52         }
53     }
54 }
55 void go()
56 {
57     for(int i=1;i<=n;i++)
58         if(!dfn[i]) dfs(i);
59     for(int i=1,num;i<=n;i++)
60     {
61         num=0;
62         for(int j=n+1;j<=n+n;j++)
63             if(belong[j]==belong[i]&&map[i][j-n]) num++;
64         printf("%d ",num);
65         for(int j=n+1;j<=n+n;j++)
66             if(belong[j]==belong[i]&&map[i][j-n]) printf("%d ",j-n);
67         printf("\n");
68     }
69 }
70 int main()
71 {
72     while(scanf("%d",&n)!=EOF)
73     {
74         read();
75         go();
76     }
77     return 0;
78 }

 

 

 

posted @ 2012-08-29 20:38  proverbs  阅读(429)  评论(0编辑  收藏  举报