zoukankan      html  css  js  c++  java
  • POJ1236_A

    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 Output

     

    1
    2
    

     

    题意

    有向图上有 N 个点,若干有向边。
    第一问:至少给几个点传递信息,才能保证信息传遍整个图。
    第二问:至少添加几条边,才能使任意选择点,都能传遍整个图。

    思路

    强连通分量的裸题。
    强连通分量内的任意一点收到消息,内部其他各点必定都能收到消息。因此,可以把每个强连通分量缩成一个点。只需要考察入度为 0 的强连通分量的个数,就是第一问的答案。
    对于第二问,是把图连接成一个强连通分量,同样可以在缩点后的图中操作。这里的做法是统计图中入度为0、出度为0的强连通分量的个数,取较大值即为第二问的答案。 本题中原图只有一个强连通分量的情况需要特判。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<vector>
      5 
      6 using namespace std;
      7 
      8 const int maxn = 100 + 10;
      9 
     10 int N;
     11 int In[maxn], Out[maxn];
     12 
     13 /***************************Tarjan算法模板***************************/
     14 vector<int> G[maxn];
     15 int Mark[maxn], Root[maxn], Stack[maxn];//时间戳,根(当前分量中时间戳最小的节点),栈
     16 bool Instack[maxn]; //是否在栈中标记
     17 int Ssc[maxn];            //每个节点所在的强连通分量的编号
     18 int Index, Ssc_n, Top;    //搜索时用的时间戳,强连通分量总数,栈顶指针
     19 
     20 void Tarjan(int u)        //u 当前搜索到的点
     21 {
     22     Mark[u] = Root[u] = ++ Index;  //每找到一个点,对时间戳和根初始化
     23     Stack[Top ++] = u;        //压栈
     24     Instack[u] = true;        //在栈中标记
     25 
     26     int v;
     27 
     28     for(int i= 0; i< G[u].size(); i++)   //向下搜索
     29     {
     30         v = G[u][i];
     31         if(Mark[v] == 0)                 //没到过的点
     32         {
     33             Tarjan(v);  //先向下搜索
     34             if(Root[u] > Root[v]) Root[u] = Root[v];//更新根
     35         }
     36         else if(Instack[v] && Root[u] > Mark[v]) Root[u] = Mark[v];  //到过的点且点仍在栈中,试着看这个点能不能成为根
     37     }
     38 /*对当前点的搜索结束*/
     39     if(Mark[u] == Root[u])  //当前点本身时根
     40     {
     41         Ssc_n ++;   //更新强连通分量数
     42 
     43         do{    //栈中比它后入栈的元素在以它为根的强连通分量中
     44             v = Stack[-- Top];
     45             Instack[v] = false;
     46             Ssc[v] = Ssc_n;//把同一个强连通分支的点做上相同标记 
     47         }while(v != u);    //直到它自己
     48     }
     49 }
     50 
     51 void SSC()
     52 {
     53     memset(Mark, 0, sizeof Mark);   //初始化时间戳和栈内标记
     54     memset(Instack, false, sizeof Instack);
     55     Index = Ssc_n = Top = 0;   //初始化时间戳,强连通分量数,栈顶指针
     56 
     57     for(int i= 1; i<= N; i++)   //保证图上所有点都访问到
     58         if(Mark[i] == 0) Tarjan(i);
     59 }
     60 /***************************Tarjan算法模板***************************/
     61 
     62 int main()
     63 {
     64     //freopen("in.txt", "r", stdin);
     65 
     66     scanf("%d", &N);
     67     for(int i= 1; i<= N; i++)
     68     {
     69         int x;
     70         while(scanf("%d", &x), x)
     71             G[i].push_back(x);
     72     }
     73 
     74     SSC();
     75 
     76     if(Ssc_n == 1)  //只有一个强连通分量的情况
     77     {
     78         cout << "1
    0
    ";
     79         return 0;
     80     }
     81 
     82     memset(In, 0, sizeof In); //求每个强连通分量的入度和出度
     83     memset(Out, 0, sizeof Out);
     84     for(int u= 1; u<= N; u++)
     85     {
     86         for(int i= 0; i< G[u].size(); i++)
     87         {
     88             int v = G[u][i];
     89             if(Ssc[u] != Ssc[v])//u,v两点不在同一个强连通分支 
     90                 Out[Ssc[u]] ++, In[Ssc[v]] ++;
     91         }
     92     }
     93 
     94     int S1 = 0, S2 = 0;//找入度为0、出度为0的点的数目
     95     for(int i= 1; i<= Ssc_n; i++)
     96     {
     97         if(In[i] == 0) S1 ++;
     98         if(Out[i] == 0) S2 ++;
     99     }
    100 
    101     cout << S1 << endl << max(S1, S2) << endl;
    102 
    103     return 0;
    104 }
  • 相关阅读:
    查询、行hbase Shell之简单命令说明by小雨
    安全模式、磁盘空间Hadoop 常见问题总结by小雨
    [wc2013]糖果公园(70分)by小雨
    方法、脚本Pig Grunt之简单命令及实例说明by小雨
    数据、进程云计算学习笔记Hadoop简介,hadoop实现原理,NoSQL介绍...与传统关系型数据库对应关系,云计算面临的挑战by小雨
    安装、进程云计算学习笔记hadoop的简介,以及安装,用命令实现对hdfs系统进行文件的上传下载by小雨
    配置文件、虚拟机如何使用vagrant在虚拟机安装hadoop集群by小雨
    请求、信息Cloud Foundry中基于Master/Slave机制的Service Gateway——解决Service Gateway单点故障问题by小雨
    格式化、问题ubuntu 12.10下搭建 hadoop 1.0.4 单机和伪分布模式by小雨
    输出、状态hadoop源码TaskAttemptID TaskTrackerAction JobTracker,FileOutputCommitter相关by小雨
  • 原文地址:https://www.cnblogs.com/hemeiwolong/p/9016737.html
Copyright © 2011-2022 走看看