Network of Schools --POJ1236 Tarjan

Network of Schools


Time Limit: 1000MS Memory Limit: 10000Kmarkdown

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.app

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.ide

Sample Input

5
2 4 3 0
4 5 0
0
0
1 0ui

Sample Output

1
2this

Source

IOI 1996spa

題意:學校鏈接到一個計算機網絡,這些學校之間達成一個協議,每個學校維護着一個學校的列表,能夠向學校列表中的學校發佈軟件。
任務A:計算爲了使每個學校都能經過網絡收到軟件,至少須要準備多少份軟件拷貝
任務B:要想確保在任意一個學校發放一個新的軟件拷貝,全部的學校均可以接受到。必須在列表中增長新的成員,計算須要增長新成員的數目。計算機網絡

思路:這是一個有向圖,則在圖中可能存在強連通份量,強連通份量中是相互鏈接,因此須要縮點,縮點之後會造成一個DAG圖,對於一個DAG圖咱們只須要在入度爲零的點都放上軟件就能夠使圖中的全部點都收到軟件,因此ansA爲入度爲零的點的數目,對於任務B則是將DAG圖構成一個強連通份量,最明顯的方式就是將出入爲零的點與入度爲零的點相連,這樣就能夠使DAG圖變成強連通的,而增長的邊的數目則要是出度爲零點的數目與入度爲零點的數目的最大值(本身畫畫就知道了)code


Tarjanip

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;

const int Max = 110;

vector <int> Map[Max];

int dfn[Max],RDu[Max],CDu[Max],low[Max],dep;

int n,num,pre[Max],vis[Max];

stack<int>S;

void init()
{
    for(int i=0;i<=n;i++)
    {
        Map[i].clear();
    }

    memset(dfn,-1,sizeof(dfn));

    memset(RDu,0,sizeof(RDu));

    memset(CDu,0,sizeof(CDu));

    memset(vis,0,sizeof(vis));
    dep = 0 ; num = 0;
}

void Tarjan(int u)//求強連通份量
{
    low[u]=dfn[u]=dep++;

    S.push(u);

    vis[u]=1;

    for(int i=0;i<Map[u].size();i++)
    {
        if(vis[Map[u][i]]==0)
        {
            Tarjan(Map[u][i]);

            low[u] = min(low[u],low[Map[u][i]]);
        }
        if(vis[Map[u][i]]==1)
        {
            low[u] = min(low[u],dfn[Map[u][i]]);
        }
    }

    if(dfn[u]==low[u])
    {
        while(!S.empty())
        {
            int v = S.top();

            S.pop();

            pre[v] = num;

            vis[v]=2;

            if(v==u)
            {
                break;
            }
        }
        num++;
    }
}

int main()
{

    while(~scanf("%d",&n))
    {

        init();

        int v;

        for(int i=1;i<=n;i++)
        {
            while(scanf("%d",&v)&&v)
            {
                Map[i].push_back(v);
            }
        }

        for(int i=1;i<=n;i++)
        {
            if(dfn[i]==-1)
            {
                Tarjan(i);
            }
        }

        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<Map[i].size();j++)
            {
                if(pre[i]!=pre[Map[i][j]])
                {
                    CDu[pre[i]]++;
                    RDu[pre[Map[i][j]]]++;
                }
            }

        }

        int ansA=0,ansB=0;


        for(int i=0;i<num;i++)
        {
            if(CDu[i]==0)
            {
                ansB++;
            }

            if(RDu[i]==0)
            {
                ansA++;
            }
        }

        ansB=max(ansA,ansB);

        if(num==1)//注意只有一個強連通的時候
        {
            ansB=0;
        }
        printf("%d\n%d\n",ansA,ansB);
    }
    return 0;
}

Kosaraju

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>

using namespace std;

const int Max = 110;

vector<int>GF[Max];

vector<int>GR[Max];

int path[Max],part[Max];

int RDu[Max],CDu[Max],Num;

bool vis[Max];

int n;

int ansA,ansB;

void Init()
{
    for(int i=0;i<=n;i++)
    {
        GF[i].clear();
        GR[i].clear();
    }

    memset(path,0,sizeof(path));

    memset(part,0,sizeof(part));

    memset(RDu,0,sizeof(RDu));

    memset(CDu,0,sizeof(CDu));

    memset(vis,false,sizeof(vis));

    Num = 0; ansA = 0; ansB = 0;
}

void DFSF(int u) //正向遍歷
{
    if(!vis[u])
    {
        vis[u]=true;

        for(int i=0;i<GF[u].size();i++)
        {
            DFSF(GF[u][i]);
        }
        path[++path[0]]=u;//這個必定放在遍歷完子節點以後
    }
}

void DFSR(int u) //反向遍歷
{
    if(!vis[u])
    {
        vis[u]=true;

        part[u]=part[0];

        for(int i=0;i<GR[u].size();i++)
        {
            DFSR(GR[u][i]);
        }
    }
}

void Kosaraju()
{
    for(int i=1;i<=n;i++)
    {   
        DFSF(i);
    }

    memset(vis,false,sizeof(vis));

    for(int i=n;i>=1;i--)
    {
        if(!vis[path[i]])
        {
            ++part[0];

            DFSR(path[i]);
        }
    }

    for(int i=1;i<=n;i++)//縮點,計算出入度
    {
        memset(vis,false,sizeof(vis));

        for(int j=0;j<GF[i].size();j++)
        {
            if(part[i]!=part[GF[i][j]]&&!vis[part[GF[i][j]]])
            {
                vis[part[GF[i][j]]]=true;

                CDu[part[i]]++;

                RDu[part[GF[i][j]]]++;
            }
        }
    }
    for(int i=1;i<=part[0];i++)// 計算答案
    {
        if(RDu[i]==0)
        {
            ansA++;
        }
        if(CDu[i]==0)
        {
            ansB++;
        }
    }
    ansB = max(ansA,ansB);

    if(part[0]==1)
    {
        ansB = 0;
    }

    printf("%d\n%d\n",ansA,ansB);
}

int main()
{
    while(~scanf("%d",&n))
    {
        Init();

        int v;

        for(int i=1;i<=n;i++)
        {
            while(scanf("%d",&v)&&v)
            {
                GF[i].push_back(v);

                GR[v].push_back(i);
            }
        }

        Kosaraju();

    }
    return 0;
}
相關文章
相關標籤/搜索