POJ 1904 King's Quest(强连通分量)
题目大意
一个国王,有 n(1<=n<=2000) 个儿子,在这个国家中有 n 个漂亮的妹子。每个儿子都有自己喜欢的妹子(可以是多个)。每个妹子只能嫁一个人,每个儿子只娶自己喜欢的人
国王的巫师调查到了每个儿子喜欢哪些妹子,并且为每一个儿子分配了他喜欢的妹子让他娶
但是国王不满意,说是要巫师统计出每个儿子能够娶哪些人,使得儿子们娶了这个妹子后,其他的每个儿子都有妹子可以娶
题目给出了每个儿子喜欢的人,以及巫师做好的一个”妹子分配“方案
好绕的题意~
做法分析
对于每个王子 A,假设他喜欢妹子 B,建边 <A, B>
对于每个婚姻分配,比如王子 A 娶妹子 B,建边 <B, A>
对建好的图缩点,处于同一个强连通分量重的王子和妹子可以混搭(前提是这个王子喜欢这个妹子)
这道题挺神的,不知道为什么 AC 的人这么多,算了,POJ 上面题目的通过量向来很奇葩。。。
参考代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <vector> 2 #include <stack> 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 8 using namespace std; 9 10 const int N=4006; 11 12 vector <int> arc[N], scc[N], ans[N]; 13 int n, T, ind; 14 int dfn[N], low[N], id[N]; 15 stack <int> s; 16 bool vs[N], love[N][N]; 17 18 void tarjan(int u) 19 { 20 s.push(u), vs[u]=1; 21 dfn[u]=low[u]=T++; 22 int len=(int)arc[u].size(); 23 for(int i=0; i<len; i++) 24 { 25 int v=arc[u][i]; 26 if(dfn[v]==-1) 27 { 28 tarjan(v); 29 if(low[u]>low[v]) low[u]=low[v]; 30 } 31 else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v]; 32 } 33 if(low[u]==dfn[u]) 34 { 35 for(int v; 1; ) 36 { 37 v=s.top(); 38 s.pop(), vs[v]=0; 39 scc[ind].push_back(v), id[v]=ind; 40 if(v==u) break; 41 } 42 ind++; 43 } 44 } 45 46 int main() 47 { 48 scanf("%d", &n); 49 for(int i=1; i<=n; i++) 50 for(int j=1; j<=n; j++) 51 love[i][j]=0; 52 for(int i=1, len, u; i<=n; i++) 53 { 54 scanf("%d", &len); 55 arc[i].clear(); 56 for(int j=0; j<len; j++) 57 { 58 scanf("%d", &u); 59 arc[i].push_back(n+u); 60 love[i][u]=1; 61 } 62 } 63 for(int i=1, u; i<=n; i++) 64 { 65 scanf("%d", &u); 66 arc[u+n].push_back(i); 67 } 68 for(int i=1; i<=n+n; i++) vs[i]=0, dfn[i]=-1, scc[i].clear(); 69 while(!s.empty()) s.pop(); 70 ind=T=0; 71 for(int i=1; i<=n+n; i++) if(dfn[i]==-1) tarjan(i); 72 for(int i=0; i<ind; i++) sort(scc[i].begin(), scc[i].end()); 73 for(int i=1; i<=n; i++) ans[i].clear(); 74 for(int i=1; i<=n; i++) 75 { 76 int u=id[i]; 77 int L=0, R=(int)scc[u].size()-1; 78 int len=R+1; 79 while(L<R) 80 { 81 int mid=(L+R)>>1; 82 if(scc[u][mid]<=n) L=mid+1; 83 else R=mid; 84 } 85 if(scc[u][L]<=n) L++; 86 for(int j=L; j<len; j++) 87 { 88 if(!love[i][scc[u][j]-n]) continue; 89 ans[i].push_back(scc[u][j]-n); 90 } 91 } 92 for(int i=1; i<=n; i++) 93 { 94 int len=(int)ans[i].size(); 95 printf("%d ", len); 96 for(int j=0; j<len; j++) 97 { 98 printf("%d", ans[i][j]); 99 if(j==len-1) printf("\n"); else printf(" "); 100 } 101 } 102 return 0; 103 }
AC通道