POJ - 1236 Network of Schools

题目链接:http://poj.org/problem?id=1236

题面:

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
Source
IOI 1996
题意:学校里有n台电脑,每台电脑都可以通过网络传达文件给指定的电脑,但是指定的电脑不一定能传回来,也就是有向图,第一个问是最少要在多少电脑上安装文件,才能使得所有电脑都能有文件,第二个问是最少要增加几条边,才能使把文件安装在任意一台电脑上,所有电脑都能有文件。

分析及思路:

首先每台电脑是一个节点,可以看出,一个环也就是强连通分量内只要有一台电脑能接收到文件,则所有这个环内的电脑都能接收到文件,因此可以把一个环看成一个点,这道题就变成了求强连通分量并且缩点的问题。缩点之后求所有点的入度和出度,显然,入度为0的点就是第一个问的答案,因为这个环没办法从别的地方接受文件,所以这个环必须自己安装一个文件,其它有入度的环都可以从别的地方接收文件。第二个问的答案则是统计入度为0的环的数量t1和出度为0的环的数量t2,答案便是t1和t2的最大值,当然需要特判一下,如果只有一个环,则答案为0。原因也不难理解。读者可以自行画图思考便可得出答案。
AC代码:

#include
#include
#include
#define rep(i,x,n) for(int i=x;i
#define per(i,x,n) for(int i=n-1;i>=x;i--)
using namespace std;
//head
const int maxn=106;
struct Edge{int to,next;}edge[100006];
int n,a,cur=0,tot=0,head[maxn],vis[maxn],low[maxn],dfn[maxn],color[maxn],out[maxn],in[maxn];
void addedge(int x){edge[cur].to=a;edge[cur].next=head[x],head[x]=cur++;}
stack<int>q;
void tarjan(int x)
{
    low[x]=dfn[x]=++tot;
    q.push(x);
    vis[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int nx=edge[i].to;
        if(!dfn[nx])
        {
            tarjan(nx);
            low[x]=min(low[x],low[nx]);
        }
        else if(vis[nx])
            low[x]=min(low[x],dfn[nx]);
    }
    if(low[x]==dfn[x])
    {
        int tmp=0;
        while(!q.empty())
        {
            tmp=q.top();
            q.pop();
            color[tmp]=cur;
            vis[tmp]=0;
            if(tmp==x)break;
        }
        cur++;
    }
}
int main()
{
     ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     memset(head,-1,sizeof(head));
     cin>>n;
     rep(i,1,n+1)
     {
         while(cin>>a&&a!=0)
             addedge(i);
     }
     cur=0;
     rep(i,1,n+1)if(!dfn[i])tarjan(i);
     if(cur==1){cout<<1<0<return 0;}
     rep(i,1,n+1)
     {
         for(int x=head[i];x!=-1;x=edge[x].next)
         if(color[i]!=color[edge[x].to]){out[color[i]]++;in[color[edge[x].to]]++;}
     }
     int t1=0,t2=0;
     rep(i,0,cur)
     {
         if(in[i]==0)t1++;
         if(out[i]==0)t2++;
     }
     cout<return 0;
}

版权声明:本文为原创文章,转载请标明出处。
https://blog.csdn.net/u014390156

你可能感兴趣的:(algorithm,tarjan)