poj 1236 Network of Schools(tarjan縮點)
阿新 • • 發佈:2017-05-18
problem lan struct http tor tar sch con vector
題目鏈接:http://poj.org/problem?id=1236
題意:給出n個學校和一些學校之間的網絡鏈接關系,學校之間的網絡是單向邊,讓你求出兩個問題的答案,1.至少需要多少份軟件,使得所有學校都可以收到。2.如果希望用一份軟件就能夠使所有學校收到需要添加幾條邊
題解:首先求強連通分量然後縮點,所謂縮點就是將一個連通圖化為一個點。然後再以聯通圖構成一個圖。
然後這題的問題1只要求聯通分量入度為0的點的和就行了,問題2就是求連通分量入度和出度為0的和的最
大值。(為了構成全連通分量構成的圖聯通,最少要加max(入度為0的,出度為0的)才能保證聯通)。
#include <iostream> #include <cstring> #include <vector> #include <cstdio> using namespace std; const int M = 10000 + 10; const int N = 100 + 10; struct TnT { int v , next; }edge[M]; int head[N] , e; int Low[N] , DFN[N] , Stack[N] , Belong[N]; int Index , top; int scc; bool Instack[N]; int num[N]; void init() { memset(head , -1 , sizeof(head)); e = 0; } void add(int u , int v) { edge[e].v = v , edge[e].next = head[u] , head[u] = e++; } void Tarjan(int u) { int v; Low[u] = DFN[u] = ++Index; Stack[top++] = u; Instack[u] = true; for(int i = head[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(!DFN[v]) { Tarjan(v); Low[u] = min(Low[u] , Low[v]); } else if(Instack[v]) Low[u] = min(Low[u] , DFN[v]); } if(Low[u] == DFN[u]) { scc++; do { v = Stack[--top]; Instack[v] = false; Belong[v] = scc; num[scc]++; } while(v != u); } } int In[N] , Out[N]; int main() { int n; while(scanf("%d" , &n) != EOF) { init(); for(int i = 1 ; i <= n ; i++) { int x; while(scanf("%d" , &x)) { if(x == 0) break; add(i , x); } } memset(DFN , 0 , sizeof(DFN)); memset(Instack , false , sizeof(Instack)); memset(num , 0 , sizeof(num)); memset(In , 0 , sizeof(In)); memset(Out , 0 , sizeof(Out)); for(int i = 1 ; i <= n ; i++) if(!DFN[i]) Tarjan(i); for(int i = 1 ; i <= n ; i++) { for(int j = head[i] ; j != -1 ; j = edge[j].next) { int v = edge[j].v; if(Belong[i] != Belong[v]) { In[Belong[v]]++; Out[Belong[i]]++; } } } int ans1 = 0 , ans2 = 0; for(int i = 1 ; i <= scc ; i++) { if(In[i] == 0) ans1++; if(Out[i] == 0) ans2++; } if(scc == 1) printf("1\n0\n"); else printf("%d\n%d\n" , ans1 , max(ans1 , ans2)); } return 0; }
poj 1236 Network of Schools(tarjan縮點)