//可作为模板,静态邻接表
//HDU1827
/*
*State: HDU1827 125MS 336K 2082 B C++ 
*题目大意:
*        wiskey大牛要通过电话通知大家,如果你有别的队员的电话,就可以有你代劳
*        通知这些人,通知每个人的话费是不一样的,wiskey要花费最少达到通知所有
*        人的目的。打电话这种模型具有传递性,用<A, B>来表示A可以通知到B,即如果
*        <A, B>,且<B, C>,则<A, C>。
*解题思路:
*        强连通分量缩点,之后求入度为0的点的个数即为最小通知人数,求缩点后,每个
*        缩点的最小通知费用,再累加入度为0的缩点的费用即为最小费用。
*/
View Code
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 using namespace std;
  5 
  6 const int MAXN = 1005;
  7 const int MAXE = 2005;
  8 int dfn[MAXN], low[MAXN], inS[MAXN];
  9 int step, scc, id[MAXN], myS[MAXN], top;
 10 int weight[MAXN], head[MAXN], cntEdge;
 11 
 12 typedef struct _node
 13 {
 14     int v, next;
 15 }N;
 16 N edge[MAXE];
 17 //缩点建有向无环图
 18 int idw[MAXN];
 19 
 20 void addEdge(int u, int v)
 21 {
 22     edge[cntEdge].v = v;
 23     edge[cntEdge].next = head[u];
 24     head[u] = cntEdge++;
 25 }
 26 
 27 void init()
 28 {
 29     cntEdge = top = 0;
 30     scc = 1;
 31     step = 0;
 32     for(int i = 0; i < MAXN; i++)
 33     {
 34         idw[i] = 0;
 35         id[i] = head[i] = -1;
 36         inS[i] = 0;
 37         dfn[i] = low[i] = -1;
 38     }
 39 }
 40 
 41 void tarjan_scc(int n)
 42 {
 43     dfn[n] = low[n] = ++step;
 44     myS[top++] = n;
 45     inS[n] = 1;
 46     for(int f = head[n]; f != -1; f = edge[f].next)
 47     {
 48         int son = edge[f].v;
 49         if(dfn[son] == -1)
 50         {
 51             tarjan_scc(son);
 52             low[n] = min(low[n], low[son]);
 53         }
 54         else if(inS[son] == 1)
 55             low[n] = min(low[n], dfn[son]);
 56     }
 57     if(dfn[n] == low[n])
 58     {
 59         int tmp, Min = INT_MAX;
 60         do
 61         {
 62             tmp = myS[--top];
 63             id[tmp] = scc;
 64             if(weight[tmp] < Min)
 65                 Min = weight[tmp];
 66             inS[tmp] = 0;
 67         }while(top != 0 && tmp != n);
 68         idw[scc] += Min;
 69         scc++;
 70     }
 71 }
 72 
 73 void deal_scc(int n, int &sol1, int &sol2)
 74 {
 75     int inTree[MAXN] = {0};
 76     for(int i = 1; i <= n; i++)
 77     {
 78         for(int j = head[i]; j != -1; j = edge[j].next)
 79         {
 80             int u = i, v = edge[j].v;
 81             if(id[u] == id[v])
 82                 continue;
 83             else
 84                 inTree[id[v]]++;
 85         }
 86     }
 87     sol1 = sol2 = 0;
 88     for(int i = 1; i < scc; i++)
 89     {
 90         if(inTree[i] == 0)
 91         {
 92             sol1++;
 93             sol2 += idw[i];
 94         }
 95     }
 96     
 97 }
 98 
 99 int main(void)
100 {
101 #ifndef ONLINE_JUDGE
102     freopen("inHDU1827.txt", "r", stdin);
103 #endif
104 
105     int n, m;
106     while(scanf("%d %d", &n, &m) == 2)
107     {
108         init();
109         int u, v;
110         for(int i = 1; i <= n; i++)
111             scanf("%d", &weight[i]);
112 
113         for(int i = 0; i < m; i++)
114         {
115             scanf("%d %d", &u, &v);
116             addEdge(u, v);
117         }
118         for(int i = 1; i <= n; i++)
119         {
120             if(dfn[i] == -1)
121                 tarjan_scc(i);
122         }
123         int sol1, sol2;
124         deal_scc(n, sol1, sol2);
125         printf("%d %d\n", sol1, sol2);
126     }
127     return 0;
128 }
posted on 2012-08-16 01:40  cchun  阅读(302)  评论(0编辑  收藏  举报