hdu 4685(强连通分量+二分图的完美匹配)
https://www.cnblogs.com/violet-acmer/p/9739990.html
参考资料:
[2]:http://www.cnblogs.com/frog112111/p/3387173.html
题意:
n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能的结婚对象。
必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了。
分析:
这题是poj 1904的加强版,poj 1904的王子和公主数是相等的,这里可以不等,且poj 1904给出了一个初始完美匹配,但是这题就要自己求。
所以只要求出完美匹配之后,就和poj 1904的做法就完全相同了。
那么怎么求出完美匹配呢?一开始我用多重匹配的匈牙利算法来做,但是怎么做都不对.......看了题解才恍然大悟=_=
先说几个坑,这题有点奇怪,就是所有王子都可以争着和同一个公主结婚,只要该王子喜欢该公主,感觉公主有点悲哀呀........
比如:
2 2
1 1
1 1
输出的答案是:
1 1
1 1
而不是
1 1
0
这里就是和poj 1904有点不一样的地方,坑了我好久.........
求完美匹配:
先对原图用匈牙利算法做一遍二分图匹配,但是还有可能剩余一些人还没匹配,只要虚拟出一些节点来匹配剩余的点就行了。
假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。
假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主
这样就构成完美匹配了,接下来就是和poj 1904一样了。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 #define pb push_back 8 #define mem(a,b) memset(a,b,sizeof a) 9 const int maxn=500+500+500+10; 10 11 int n,m; 12 //===========匈牙利=========== 13 struct Node 14 { 15 int matchM[maxn]; 16 int matchW[maxn]; 17 bool check[maxn]; 18 vector<int >edge[maxn]; 19 void Init() 20 { 21 mem(matchM,-1); 22 mem(matchW,-1); 23 for(int i=0;i < maxn;++i) 24 edge[i].clear(); 25 } 26 void addEdge(int u,int v){ 27 edge[u].pb(v); 28 } 29 bool Dfs(int u) 30 { 31 for(int i=0;i < edge[u].size();++i) 32 { 33 int to=edge[u][i]; 34 if(!check[to]) 35 { 36 check[to]=true; 37 if(matchW[to] == -1 || Dfs(matchW[to])) 38 { 39 matchW[to]=u; 40 matchM[u]=to; 41 return true; 42 } 43 } 44 } 45 return false; 46 } 47 void Hungarian() 48 { 49 for(int i=1;i <= n;++i) 50 { 51 mem(check,false); 52 Dfs(i); 53 } 54 } 55 }_match; 56 //============================ 57 //============SCC============= 58 int scc[maxn]; 59 bool vis[maxn]; 60 vector<int >vs; 61 vector<int >edge[maxn],redge[maxn]; 62 void addEdge(int u,int v) 63 { 64 edge[u].pb(v); 65 redge[v].pb(u); 66 } 67 void Dfs(int u) 68 { 69 vis[u]=true; 70 for(int i=0;i < edge[u].size();++i) 71 { 72 int to=edge[u][i]; 73 if(!vis[to]) 74 Dfs(to); 75 } 76 vs.pb(u); 77 } 78 void rDfs(int u,int sccId) 79 { 80 scc[u]=sccId; 81 vis[u]=true; 82 for(int i=0;i < redge[u].size();++i) 83 { 84 int to=redge[u][i]; 85 if(!vis[to]) 86 rDfs(to,sccId); 87 } 88 } 89 void Scc() 90 { 91 mem(vis,false); 92 vs.clear(); 93 for(int i=1;i <= n;++i) 94 if(!vis[i]) 95 Dfs(i); 96 mem(vis,false); 97 int sccId=0; 98 for(int i=vs.size()-1;i >= 0;--i) 99 { 100 int to=vs[i]; 101 if(!vis[to]) 102 rDfs(to,++sccId); 103 } 104 } 105 //============================ 106 void Init() 107 { 108 _match.Init(); 109 for(int i=0;i < maxn;++i) 110 edge[i].clear(),redge[i].clear(); 111 } 112 int main() 113 { 114 int T; 115 scanf("%d",&T); 116 for(int kase=1;kase <= T;++kase) 117 { 118 Init(); 119 scanf("%d%d",&n,&m); 120 for(int i=1;i <= n;++i) 121 { 122 int k; 123 scanf("%d",&k); 124 while(k--) 125 { 126 int v; 127 scanf("%d",&v); 128 addEdge(i,v+n); 129 _match.addEdge(i,v+n); 130 } 131 } 132 _match.Hungarian();//匈牙利算法求最大匹配 133 int all=n+m; 134 for(int i=1;i <= n;++i) 135 { 136 if(_match.matchM[i] == -1)//为剩余王子匹配虚拟公主 137 { 138 all++; 139 for(int j=1;j <= n;++j)//所有王子都喜欢该虚拟公主 140 addEdge(j,all); 141 _match.matchM[i]=all; 142 _match.matchW[all]=i; 143 } 144 } 145 for(int i=n+1;i <= n+m;++i) 146 { 147 if(_match.matchW[i] == -1)//为剩余公主匹配虚拟王子 148 { 149 all++; 150 for(int j=n+1;j <= n+m;++j)//该虚拟王子喜欢所有公主 151 addEdge(all,j); 152 _match.matchM[all]=i; 153 _match.matchW[i]=all; 154 } 155 } 156 for(int i=1;i <= all;++i) 157 if(_match.matchM[i] != -1)//所有与王子匹配的公主建一条边连向王子 158 addEdge(_match.matchM[i],i); 159 Scc();//求强连通分量 160 printf("Case #%d:\n",kase); 161 for(int i=1;i <= n;++i) 162 { 163 int res=0; 164 int ans[maxn]; 165 for(int j=0;j < edge[i].size();++j) 166 { 167 int to=edge[i][j]; 168 if(scc[i] == scc[to] && to <= m+n)//剔除掉虚拟的公主 169 ans[res++]=to-n; 170 } 171 sort(ans,ans+res); 172 printf("%d",res); 173 for(int i=0;i < res;++i) 174 printf(" %d",ans[i]); 175 printf("\n"); 176 } 177 } 178 }