Poj--1904(图论,强连通分量)
2014-10-13 17:16:55
思路:首先根据王子喜欢的公主建边:王子 -> 女孩,然后根据wizard给出的list建反向边:女孩 -> 王子。然后求强连通分量,每个王子能结婚的女孩与他在同一个强连通分量里且是他喜欢的。至于为什么这样做,我的想法是:如果我们要改变wizard给出的正确的匹配list,设我们要互换王子A和王子B的选择(两人的选择令为A->a,B->b),那么一定要有A->b,B->a这两条边存在。拓展一下如果王子集合A1,A2。。。AK的选择中任意一对能互换,那么Ai要连着A1~AK所有选择的女孩。而题目中要求的就是那么几个尽量大的满足互换要求的王子集合,那么我们只要根据wizard给出的list建反向边,这些集合就会构成强连通分量。(ai -> Ai -> aj -> Aj -> ak -> Ak -> .... -> ai,会形成这样一种回路,A是王子,a是女孩)
1 /************************************************************************* 2 > File Name: 1904.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Sun 12 Oct 2014 04:05:27 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 const int maxn = 4010; 27 28 int first[maxn],next[200000 + maxn],ver[200000 + maxn],ecnt; 29 int dfn[maxn],low[maxn],sc[maxn],scnt,tot; 30 int N; 31 stack<int> S; 32 33 inline int Read(){ 34 int x = 0; char c; 35 while(c < '0' || c >'9') c = getchar(); 36 while(c >= '0' && c <= '9'){ 37 x = x * 10 + c - '0'; 38 c = getchar(); 39 } 40 return x; 41 } 42 43 void Add_edge(int u,int v){ 44 next[++ecnt] = first[u]; 45 ver[ecnt] = v; 46 first[u] = ecnt; 47 } 48 49 void Dfs(int p){ 50 dfn[p] = low[p] = ++tot; 51 S.push(p); 52 for(int i = first[p]; i != -1; i = next[i]){ 53 int v = ver[i]; 54 if(!dfn[v]){ 55 Dfs(v); 56 low[p] = min(low[p],low[v]); 57 } 58 else if(!sc[v]){ 59 low[p] = min(low[p],dfn[v]); 60 } 61 } 62 if(low[p] == dfn[p]){ 63 ++scnt; 64 while(1){ 65 int x = S.top(); S.pop(); 66 sc[x] = scnt; 67 if(x == p) break; 68 } 69 } 70 } 71 72 void Tarjan(){ 73 memset(low,0,sizeof(low)); 74 memset(dfn,0,sizeof(dfn)); 75 memset(sc,0,sizeof(sc)); 76 for(int i = 1; i <= 2 * N; ++i){ 77 if(!dfn[i]) Dfs(i); 78 } 79 } 80 81 void Init(){ 82 memset(first,-1,sizeof(first)); 83 while(!S.empty()) S.pop(); 84 ecnt = tot = scnt = 0; 85 } 86 87 int main(){ 88 int k,a; 89 N = Read(); 90 Init(); 91 for(int i = 1; i <= N; ++i){ 92 k = Read(); 93 while(k--){ 94 a = Read(); 95 Add_edge(i,a + N); 96 } 97 } 98 for(int i = 1; i <= N; ++i){ 99 a = Read(); 100 Add_edge(a + N,i); 101 } 102 Tarjan(); 103 int ans[maxn]; 104 for(int i = 1; i <= N; ++i){ 105 int cnt = 0; 106 for(int j = first[i]; j != -1; j = next[j]){ 107 int v = ver[j]; 108 if(sc[v] == sc[i]) ans[++cnt] = v - N; 109 } 110 printf("%d",cnt); 111 sort(ans + 1,ans + cnt + 1); 112 for(int j = 1; j <= cnt; ++j) 113 printf(" %d",ans[j]); 114 puts(""); 115 } 116 return 0; 117 }

浙公网安备 33010602011771号