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 }

 

posted @ 2014-10-13 17:37  Naturain  阅读(151)  评论(0)    收藏  举报