1. 程式人生 > >poj 1236 Network of Schools(tarjan縮點)

poj 1236 Network of Schools(tarjan縮點)

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縮點)