求出强连通分量,因为强连通中只要有一个人被通知到了,所有人都能被通知到。
缩点以后形成一个DAG,找出那些入度为0的点,累加上它们的权值就是答案。一个点的权值等于SCC中权值最小的那个点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 ", ans1, ans2); 86 } 87 88 return 0; 89 }