標籤:
題目連結:http://poj.org/problem?id=1236
題目大意:N(2<N<100)個學校之間有單向的網路,每個學校得到一套軟體後,可以通過單向網路向周邊的學校傳輸。
問題1:初始至少需要向多少個學校發放軟體,使得網路內所有的學校最終都能得到軟體。
問題2:至少需要添加幾條傳輸線路(邊),使任意向一個學校發放軟體後,經過若干次傳送,網路內所有的學校最終都能得到軟體。
解題思路:首先用tarjan求得所有強聯通分量,將每個強聯通分量看成一個點,這樣會得到一個有向非循環圖DAG, 那麼對於問題一隻需要要找出DAG圖上有多少個入度為0的點,對於問題二需要在DAG圖上找出度為0的點的個數, 然後與問題一入度為0的點的個數取最大值, 就是問題二的答案。
需要注意的是只有一個強聯通分量的時候, 需要特判一下。
代碼如下:
#include <stdio.h>#include <vector>#include <string.h>#include <algorithm>using namespace std;const int N = 103;vector<int>vec[N], stk;bool mp[N][N], in_stk[N];int low[N], dfn[N], tot, cou_scc;int belong[N];int n;void tarjan(int u, int f){ dfn[u] = low[u] = tot ++; stk.push_back(u), in_stk[u] = true; for(int i=0; i < vec[u].size(); ++ i) { int v = vec[u][i]; if(dfn[v] == -1) { tarjan(v, u); low[u] = min(low[u], low[v]); } else if(in_stk[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { ++ cou_scc; while(1) { int v = stk.back(); stk.pop_back(); in_stk[v] = false; belong[v] = cou_scc; if(u == v) break; } }}int main(){ while(scanf("%d", &n) != EOF) { memset(mp, false, sizeof(mp)); for(int i=1; i<=n; ++ i) { vec[i].clear(); int c; while(scanf("%d", &c), c) { vec[i].push_back(c); mp[i][c] = true; } } memset(low, -1, sizeof(low)); memset(dfn, -1, sizeof(dfn)); memset(belong, -1, sizeof(belong)); memset(in_stk, false, sizeof(in_stk)); cou_scc = 0, tot = 1; stk.clear(); for(int i=1; i<=n; ++ i) { if(dfn[i] == -1) tarjan(i, -1); } int in[N], out[N]; memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); for(int i=1; i<=n; ++ i) { for(int j=1; j<=n; ++ j) { if(mp[i][j] && belong[i] != belong[j]) { ++ in[belong[j]]; ++ out[belong[i]]; } } } if(cou_scc == 1) { printf("1\n0\n"); continue; } int x = 0, y = 0; for(int i=1; i<=cou_scc; ++ i) { if(in[i] == 0) ++ x; if(out[i] == 0) ++ y; } printf("%d\n%d\n", x, max(x, y)); }}View Code
POJ 1236-Network of Schools (圖論-有向圖強聯通tarjan)