hdu 4685(匹配+强连通分量)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685

思路:想了好久,终于想明白了,懒得写了,直接copy大牛的思路了,写的非常好!

做法是先求一次最大匹配设为cnt,那么左边有n-cnt个王子还未匹配,右边有m-cnt个公主还未匹配,因此我们将左侧增加m-cnt个虚拟王子,虚拟王子与右边所有公主连边;右边增加n-cnt个虚拟公主,虚拟公主与左边所有王子连边,这样我们就得到一个两边各有M=n+m-cnt的二分图,且该二分图是一个完美匹配。也就是每个王子都有一个匹配的公主。现在,我们将每个王子匹配的公主向该王子喜欢的公主连边(建一个新图g),然后求g的强连通分量。那么与每个王子之前匹配的公主在一个强连通分量里的公主都可以作为该王子的匹配使得最大匹配不变。为什么是这样的呢?设王子i之前的匹配为p[i],现在为王子i选择一个新的公主j,那么我们若能为p[i]重新找到一个王子k,那么实质上就是找到另一个王子互换两个两个王子喜欢的公主。因此两公主若在一个强连通分量里,那么王子由之前的匹配公主A选择公主B时,A也能找到另一个匹配,因为B能够通过某些路径到达A,等价于这条环上所有王子的匹配都后移一个人而已。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<vector>
  7 using namespace std;
  8 #define MAXN 1111
  9 
 10 int n,m,N,cnt;
 11 bool map[MAXN][MAXN];
 12 bool mark[MAXN];
 13 int ly[MAXN];
 14 int lx[MAXN];
 15 
 16 int dfs(int u,int m)
 17 {
 18     for(int v=1;v<=m;v++){
 19         if(map[u][v]&&!mark[v]){
 20             mark[v]=true;
 21             if(ly[v]==-1||dfs(ly[v],m)){
 22                 ly[v]=u;
 23                 lx[u]=v;
 24                 return 1;
 25             }
 26         }
 27     }
 28     return 0;
 29 }
 30                 
 31 
 32 int MaxMatch(int n,int m)
 33 {
 34     memset(ly,-1,sizeof(ly));
 35     memset(lx,-1,sizeof(lx));
 36     int ans=0;
 37     for(int i=1;i<=n;i++){
 38         memset(mark,false,sizeof(mark));
 39         ans+=dfs(i,m);
 40     }
 41     return ans;
 42 }
 43 
 44 vector<vector<int> >g;
 45 vector<vector<int> >ans;
 46 
 47 int dfn[MAXN],low[MAXN];
 48 int color[MAXN],_count;
 49 stack<int>S;
 50 
 51 void Tarjan(int u)
 52 {
 53     low[u]=dfn[u]=++cnt;
 54     mark[u]=true;
 55     S.push(u);
 56     for(int i=0;i<g[u].size();i++){
 57         int v=g[u][i];
 58         if(dfn[v]==0){
 59             Tarjan(v);
 60             low[u]=min(low[u],low[v]);
 61         }else if(mark[v]){
 62             low[u]=min(low[u],dfn[v]);
 63         }
 64     }
 65     if(low[u]==dfn[u]){
 66         _count++;
 67         int x;
 68         do{
 69             x=S.top();
 70             S.pop();
 71             mark[x]=false;
 72             color[x]=_count;
 73         }while(x!=u);
 74     }
 75 }
 76 
 77 
 78 
 79 int main()
 80 {
 81     int _case,k,x,t=1;
 82     scanf("%d",&_case);
 83     while(_case--){
 84         scanf("%d%d",&n,&m);
 85         memset(map,false,sizeof(map));
 86         for(int i=1;i<=n;i++){
 87             scanf("%d",&k);
 88             while(k--){
 89                 scanf("%d",&x);
 90                 map[i][x]=true;
 91             }
 92         }
 93         cnt=MaxMatch(n,m);
 94         N=n+m-cnt;
 95         for(int i=n+1;i<=N;i++)
 96             for(int j=1;j<=N;j++)
 97                 map[i][j]=true;
 98         for(int i=m+1;i<=N;i++)
 99             for(int j=1;j<=N;j++)
100                 map[j][i]=true;
101         MaxMatch(N,N);
102         g.clear();
103         g.resize(N+2);
104         ans.clear();
105         ans.resize(N+2);
106         for(int i=1;i<=N;i++){
107             for(int j=1;j<=N;j++){
108                 if(lx[i]!=j&&map[i][j]){
109                     g[lx[i]].push_back(j);
110                 }
111             }
112         }
113         memset(dfn,0,sizeof(dfn));
114         memset(mark,false,sizeof(mark));
115         _count=cnt=0;
116         for(int i=1;i<=N;i++)
117             if(dfn[i]==0)Tarjan(i);
118         for(int i=1;i<=n;i++){
119             for(int j=1;j<=m;j++){
120                 if(map[i][j]&&color[lx[i]]==color[j]){
121                     ans[i].push_back(j);
122                 }
123             }
124         }
125         printf("Case #%d:\n",t++);
126         for(int i=1;i<=n;i++){
127             printf("%d",(int)ans[i].size());
128             for(int j=0;j<ans[i].size();j++){
129                 printf(" %d",ans[i][j]);
130             }
131             puts("");
132         }
133     }
134     return 0;
135 }
View Code

 

 

 

posted @ 2013-09-12 21:32  ihge2k  阅读(1247)  评论(0编辑  收藏  举报