• POJ 1236 Network of Schools (有向图的强连通分量)


    Network of Schools
    Time Limit: 1000MS   Memory Limit: 10000K

    Description

    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 Output1

    2


    题目大意:有N个学校,从每个学校都能从一个单向网络到另外一个学校,两个问题
    1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
    2:至少需要添加几条边,使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
    用Tarjan将强连通分量求出来缩点,得到一个scc的图
    统计这个图有多少个入度为0的点ans1,出度为0的点ans2
    则第一个问就是ans1,第二个就是max(ans1,ans2)
    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    using namespace std;
    
    const int MAXN = 100+10;
    const int MAXE = 100*100+100;
    
    struct Edge{
        int to,next;
    };
    Edge edge[MAXE];
    int head[MAXN],tot;
    int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
    int Index,top;
    int scc;
    bool Instack[MAXN];
    
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
    }
    
    void addedge(int u,int v)
    {
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    
    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){
            v=edge[i].to;
            if(!DFN[v]){
                Tarjan(v);
                if(Low[u]>Low[v]) Low[u]=Low[v];
            }
            else if(Instack[v]&&Low[u]>DFN[v])
                Low[u]=DFN[v];
        }
        if(DFN[u]==Low[u]){
            scc++;
            do{
                v=Stack[--top];
                Belong[v]=scc;
                Instack[v]=false;
            }
            while(v!=u);
        }
    }
    
    void solve(int n)
    {
        memset(DFN,0,sizeof(DFN));
        memset(Instack,false,sizeof(Instack));
        Index=top=scc=0;
        for(int i=1;i<=n;i++)
            if(!DFN[i])
               Tarjan(i);
    }
    
    int in[MAXN],out[MAXN];
    
    int main()
    {
        int n;
        int v;
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++){
            while(scanf("%d",&v)==1&&v)
                addedge(i,v);
        }
        solve(n);
        if(scc==1){
            printf("1
    0
    ");
            return 0;
        }
        for(int i=1;i<=scc;i++)
            in[i]=out[i]=0;
        for(int u=1;u<=n;u++){
            for(int i=head[u];i!=-1;i=edge[i].next){
                v=edge[i].to;
                if(Belong[u]==Belong[v]) continue;
                out[Belong[u]]++;
                in[Belong[v]]++;
            }
        }
        int ans1=0,ans2=0;
        for(int i=1;i<=scc;i++){
            if(in[i]==0) ans1++;
            if(out[i]==0) ans2++;
        }
        printf("%d
    %d
    ",ans1,max(ans1,ans2));
    
        return 0;
    }
     
  • 相关阅读:
    zzuli oj 1120 最值交换
    zzuli oj 1119 一维数组排序
    zzuli oj 1118 数列有序
    zzuli oj 1117 查找数组元素
    寒假集训 字符串专题 1001
    zzuli oj 1116
    A
    Codeforces Round #615 (Div. 3) E. Obtain a Permutation
    Codeforces Round #615 (Div. 3) F. Three Paths on a Tree
    Codeforces Round #603 (Div. 2)F. Economic Difficulties
  • 原文地址:https://www.cnblogs.com/wangdongkai/p/5603849.html
Copyright © 2020-2023  润新知