zoukankan      html  css  js  c++  java
  • 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;
    }
     
  • 相关阅读:
    centos7安装nginx
    linux经常使用的命令
    linux 安装 VNC
    linux配置yum源
    docker服务器、以及容器设置自动启动
    docker初步学习以及常用命令
    Docker命令详解(run篇)
    Linux scp命令
    Linux常用命令学习31个
    Linux下解压tar.xz文件
  • 原文地址:https://www.cnblogs.com/wangdongkai/p/5603849.html
Copyright © 2011-2022 走看看