HDU 1827:Summer Holiday(强连通)

http://acm.hdu.edu.cn/showproblem.php?pid=1827

思路:强连通分量缩点后找入度为0的点,然后对于属于该强连通分量的找一个最小耗费的入口。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <queue>
  6 #include <cmath>
  7 #include <map>
  8 #include <vector>
  9 #include <stack>
 10 using namespace std;
 11 #define N 80010
 12 #define M 30010
 13 #define INF 0x3f3f3f3f
 14 struct node
 15 {
 16     int u, v, next;
 17 }edge[N*2];
 18 stack<int> sta;
 19 int tot, cnt, num, head[N], belong[N], dfn[N], low[N], n, m, a[N], in[N], mi[N];
 20 bool vis[N];
 21 
 22 void init()
 23 {
 24     tot = cnt = num = 0;
 25     while(sta.size()) sta.pop();
 26     memset(head, -1, sizeof(head));
 27     memset(belong, 0, sizeof(belong));
 28     memset(dfn, 0, sizeof(dfn));
 29     memset(low, 0, sizeof(low));
 30     memset(vis, false, sizeof(vis));
 31     memset(in, 0, sizeof(in));
 32     memset(mi, INF, sizeof(mi));
 33 }
 34 
 35 void add(int u, int v)
 36 {
 37     edge[tot].u = u; edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot++;
 38 }
 39 
 40 void tarjan(int u)
 41 {
 42     vis[u] = 1;
 43     sta.push(u);
 44     dfn[u] = low[u] = ++cnt;
 45     for(int i = head[u]; ~i; i = edge[i].next) {
 46         int v = edge[i].v;
 47         if(!dfn[v]) {
 48             tarjan(v);
 49             if(low[v] < low[u]) low[u] = low[v];
 50         } else if(vis[v]) {
 51             if(dfn[v] < low[u]) low[u] = dfn[v];
 52         }
 53     }
 54     if(dfn[u] == low[u]) {
 55         ++num;
 56         int top = -1;
 57         while(top != u) {
 58             top = sta.top(); sta.pop();
 59             belong[top] = num;
 60             vis[top] = 0;
 61         }
 62     }
 63 }
 64 
 65 int main()
 66 {
 67     while(~scanf("%d%d", &n, &m)) {
 68         init();
 69         for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
 70         for(int i = 0; i < m; i++) {
 71             int u, v;
 72             scanf("%d%d", &u, &v);
 73             add(u, v);
 74         }
 75         for(int i = 1; i <= n; i++)
 76             if(!dfn[i]) tarjan(i);
 77         for(int u = 1; u <= n; u++) {
 78             for(int i = head[u]; ~i; i = edge[i].next) {
 79                 int v = edge[i].v;
 80                 if(belong[u] != belong[v]) { //缩点后找入度为0的点
 81                     in[belong[v]]++;
 82                 }
 83             }
 84         }
 85         int ans = 0, sum = 0;
 86         for(int i = 1; i <= num; i++) {
 87             if(!in[i]) {
 88                 ans++;
 89                 for(int j = 1; j <= n; j++) {
 90                     if(belong[j] == i) {
 91                         if(a[j] < mi[i]) {
 92                             mi[i] = a[j]; //对于不同的强连通分量之间找耗费最小的入口
 93                         }
 94                     }
 95                 }
 96                 sum += mi[i];
 97             }
 98         }
 99         printf("%d %d
", ans, sum);
100     }
101     return 0;
102 }
103 
104 /*
105 4 3
106 1 2 3 4
107 1 2
108 1 3
109 1 4
110 */
原文地址:https://www.cnblogs.com/fightfordream/p/5929270.html