1. 程式人生 > >Network of Schools (Tarjan模板縮點)

Network of Schools (Tarjan模板縮點)

A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school. Input The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line. Output Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B. Sample Input 5 2 4 3 0 4 5 0 0 0 1 0 Sample Output 1 2

我們先通過Tarjan演算法縮點將圖變成DAG圖(有向無環圖),接下來任務A是求最少發幾套軟體可以全覆蓋,首先題意已經保證了是連通的。然後我們可以想,如果我們把所有沒有入邊的點都放上軟體,是一定可行的。有入邊的一定會通過一些邊最終從一定有出邊的發放軟體的地方獲得軟體。 然後看任務B是至少加多少邊將該圖成為強連通圖。如果我們有些點沒有入點,有些點沒出點。那我們如果想辦法將入點和一些出點相連,就能保證最後會成為很多環相連。這樣子答案就是沒有入邊的點和沒有出邊的點的最大值。這樣每個點既有入邊和出邊。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const int N = 210;

vector<int>ve[N];
int in[N];
int out[N];
int vis[N],dfn[N],low[N],color[N];
int n,m,t,cnt,sig;
//模擬棧
int sta[N];

void init()
{
    for(int i = 1;i <= n;++i) ve[i].clear();
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
}

void Tarjan(int u)
{
    vis[u] = 1;
    dfn[u] = low[u] = cnt++;
    sta[++t] = u;
    int len = ve[u].size();
    for(int i = 0;i < len;++i){
        int v = ve[u][i];
        if(vis[v] == 0) Tarjan(v);
        if(vis[v] == 1) low[u] = min(low[u],low[v]);
    }
    if(dfn[u] == low[u]){
        sig++;
        do{
            color[sta[t]] = sig;
            vis[sta[t]] = -1;
        }while(sta[t--] != u);
    }
}

void solve()
{
    t = -1;sig = 0,cnt = 1;
    for(int i = 1;i <= n;++i){
        if(vis[i] == 0){
            Tarjan(i);
        }
    }
    if(sig == 1){
        printf("1\n0\n");
        return ;
    }
    for(int i = 1;i <= n;++i){
        int len = ve[i].size();
        for(int j = 0;j < len;++j){
            int v = ve[i][j];
            if(color[i] != color[v]){
                in[color[v]]++;
                out[color[i]]++;
            }
        }
    }
    int ans1 = 0,ans2 = 0;
    for(int i = 1;i <= sig;++i){
        if(in[i] == 0) ans1++;
        if(out[i] == 0) ans2++;
    }
    printf("%d\n%d\n",ans1,max(ans1,ans2));
}

int main()
{
    while(~scanf("%d",&n)){
        init();
        for(int i = 1;i <= n;++i){
            int x;
            while(~scanf("%d",&x)){
                if(x == 0) break;
                ve[i].pb(x);
            }
        }
        solve();
    }
    return 0;
}