Poj - 1236 Network of Schools(縮點)(有向圖加邊變成強連通圖)

題目鏈接
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的點的個數a,出度爲0的點的個數b,至少添加max(a,b)個邊,能夠使得他們變成強連通圖。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN = 11000;
struct Edge
{
    int v;
    int next;
}e[MAXN];
int head[MAXN];
int dfn[MAXN],low[MAXN];
bool vis[MAXN];
int stact[MAXN];
int belong[MAXN],num[MAXN];
//belong表示每個點屬於的縮完之後的哪一個點,num表示每一個縮點裏面有多少個點
int inde[MAXN];//表示每個縮點的入讀
int outde[MAXN];//每個縮點的出度
int cnt,tot,index,now;
int n;

void add(int u,int v)
{
    e[cnt].next = head[u];
    e[cnt].v = v;
    head[u] = cnt++;
}

void Tarjan(int x)
{
    low[x] = dfn[x] = ++tot;
    vis[x] = 1;
    stact[++index] = x;

    for(int i = head[x];i != -1; i = e[i].next)
    {
        int v = e[i].v;
        if(!dfn[v])
        {
            Tarjan(v);
            low[x] = min(low[x], low[v]);
        }
        else if(vis[v])
            low[x] = min(low[x], dfn[v]);
    }
    if(low[x] == dfn[x])
    {
        ++now;
        do
        {
            vis[stact[index]] = 0;
            belong[stact[index]] = now;
            num[now] ++;
            index --;
        }while(x != stact[index+1]);
    }
    return ;
}

void init()
{
    for(int i = 0;i<=n;i++){
        head[i] = -1;
        num[i] = belong[i] = dfn[i] = low[i] = 0;
        inde[i] = outde[i] = 0;
        vis[i] = false;
    }
    cnt = tot = index = now = 0;
}

int main()
{
    scanf("%d",&n);
    init();
    int x;
    for(int i=1;i<=n;i++){
        while(scanf("%d",&x),x)
            add(i,x);
    }
    for(int i = 1;i <= n;i ++)
        if(!dfn[i])
            Tarjan(i);
    //縮點完成之後,我們就一定沒有環的存在
    int u,v;
    for(int i = 1;i <= n;i ++){
        for(int j = head[i];~j;j=e[j].next){
            int v = e[j].v;
            //表示如果這條邊不在縮點之內,那麼就是用來連接縮點
            if(belong[i] != belong[v]){
                inde[belong[v]] ++;
                outde[belong[i]] ++;
            }
        }
    }
    int a = 0,b = 0;
    //分別計算所的縮點中,入度和出度爲0的數目
    for(int i = 1;i <= now;i ++)
    {
        if(!inde[i]) a++;
        if(!outde[i]) b++;
    }
    printf("%d\n",a);
    if(now == 1)
        //如果所有的縮點只有一個,則不需要添加新邊
        printf("0\n");
    else
        printf("%d\n",max(a,b));
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章