POJ1904 King's Quest(Tarjan 求缩点)

  题意,给出每个儿子喜欢的mm的编号,然后再给一个原定的配对序列,求出每个儿子可以泡的mm,并保证每个儿子都有mm泡。

  思路:看得大牛的思路,比如儿子u喜欢mm v,则u -> v建一条边。给出的配对序列中,儿子u要泡v则 v -> u建一条边。然后得到一个有向图,然后求出强连通分量。就ok啦

ps:1wa没有初始化,2wa结果没有排序输出。。。一个国王搞出2000个儿子,Orz~~

渣代码:

View Code
 1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <stack>
5 #include <algorithm>
6
7 using namespace std;
8
9 const int N = 4005;
10 const int M = 400005;
11
12 struct node {
13 int to;
14 int next;
15 } g[M];
16
17 int head[N], scc[N];
18 int dfn[N], low[N];
19 int t, ind, cnt;
20 bool vis[N];
21
22 stack<int> s;
23
24 void init() {
25 for(int i = 0; i < N; i++) {
26 head[i] = dfn[i] = low[i] = scc[i] = vis[i] = 0;
27 }
28 t = 1; ind = cnt = 0;
29 }
30
31 void add(int u, int v) {
32 g[t].to = v; g[t].next = head[u]; head[u] = t++;
33 }
34
35 void tarjan(int u) {
36 int v, i;
37 dfn[u] = low[u] = ++ind;
38 s.push(u); vis[u] = true;
39 for(i = head[u]; i; i = g[i].next) {
40 v = g[i].to;
41 if(!dfn[v]) {
42 tarjan(v);
43 low[u] = min(low[v], low[u]);
44 } else if(vis[v]) {
45 low[u] = min(dfn[v], low[u]);
46 }
47 }
48 if(low[u] == dfn[u]) {
49 cnt++;
50 do {
51 v = s.top(); s.pop();
52 scc[v] = cnt;
53 //printf("%d %d\n", v, cnt);
54 vis[v] = false;
55 } while(v != u);
56 }
57 }
58
59 int main() {
60 //freopen("data.in", "r", stdin);
61
62 int n, m, j;
63 int i, v;
64 int ans[N];
65 while(~scanf("%d", &n)) {
66 init();
67 for(i = 1; i <= n; i++) {
68 scanf("%d", &m);
69 while(m--) {
70 scanf("%d", &v);
71 add(i, n+v);
72 //printf("%d %d\n", i, n+v);
73 }
74 }
75 for(i = 1; i <= n; i++) {
76 scanf("%d", &v);
77 add(n+v, i);
78 }
79 for(i = 1; i <= 2*n; i++) {
80 if(!dfn[i]) tarjan(i);
81 }
82 for(i = 1; i <= n; i++) {
83 m = 0;
84 for(j = head[i]; j; j = g[j].next) {
85 v = g[j].to;
86 if(scc[v] == scc[i]) {
87 ans[m++] = v-n;
88 }
89 }
90 sort(ans, ans + m);
91 printf("%d", m);
92 for(j = 0; j < m ;j++) {
93 printf(" %d", ans[j]);
94 }
95 cout << endl;
96 }
97 }
98 return 0;
99 }



posted @ 2012-02-13 15:37  AC_Von  阅读(280)  评论(0编辑  收藏  举报