HDU 1827 强连通 缩点 Summer Holiday

求出强连通分量,因为强连通中只要有一个人被通知到了,所有人都能被通知到。

缩点以后形成一个DAG,找出那些入度为0的点,累加上它们的权值就是答案。一个点的权值等于SCC中权值最小的那个点。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <vector>
 6 #include <stack>
 7 using namespace std;
 8 
 9 const int maxn = 1000 + 10;
10 
11 int n, m;
12 int w[maxn], cost[maxn];
13 vector<int> G[maxn];
14 
15 stack<int> S;
16 int pre[maxn], lowlink[maxn], sccno[maxn];
17 int dfs_clock, scc_cnt;
18 
19 void dfs(int u)
20 {
21     pre[u] = lowlink[u] = ++dfs_clock;
22     S.push(u);
23     for(int i = 0; i < G[u].size(); i++)
24     {
25         int v = G[u][i];
26         if(!pre[v])
27         {
28             dfs(v);
29             lowlink[u] = min(lowlink[u], lowlink[v]);
30         }
31         else if(!sccno[v]) lowlink[u] = min(lowlink[u], pre[v]);
32     }
33     if(lowlink[u] == pre[u])
34     {
35         scc_cnt++;
36         for(;;)
37         {
38             int x = S.top(); S.pop();
39             sccno[x] = scc_cnt;
40             if(x == u) break;
41         }
42     }
43 }
44 
45 void find_scc()
46 {
47     dfs_clock = scc_cnt = 0;
48     memset(sccno, 0, sizeof(sccno));
49     memset(pre, 0, sizeof(pre));
50     for(int i = 1; i <= n; i++) if(!pre[i]) dfs(i);
51 }
52 
53 int indeg[maxn];
54 
55 int main()
56 {
57     while(scanf("%d%d", &n, &m) == 2)
58     {
59         for(int i = 1; i <= n; i++) G[i].clear();
60         for(int i = 1; i <= n; i++) scanf("%d", w + i);
61         while(m--)
62         {
63             int u, v; scanf("%d%d", &u, &v);
64             G[u].push_back(v);
65         }
66 
67         find_scc();
68 
69         memset(cost, 0x3f, sizeof(cost));
70         for(int i = 1; i <= n; i++) cost[sccno[i]] = min(cost[sccno[i]], w[i]);
71 
72         memset(indeg, 0, sizeof(indeg));
73         for(int i = 1; i <= n; i++)
74         {
75             for(int j = 0; j < G[i].size(); j++)
76             {
77                 int u = sccno[i], v = sccno[G[i][j]];
78                 if(u == v) continue;
79                 indeg[v]++;
80             }
81         }
82 
83         int ans1 = 0, ans2 = 0;
84         for(int i = 1; i <= scc_cnt; i++) if(!indeg[i]) { ans1++; ans2 += cost[i]; }
85         printf("%d %d\n", ans1, ans2);
86     }
87 
88     return 0;
89 }
代码君

 

posted @ 2015-08-10 11:34  AOQNRMGYXLMV  阅读(161)  评论(0编辑  收藏  举报