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 }