POJ 1236 学校网络间的强连通

题目大意:

N个学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输。 问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。 问题2:至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

链接http://vjudge.net/problem/viewProblem.action?id=17001

每个强连通分量内只要有任意一个学校获得一份软件就可以了,因为强连通分量内的任意两点是相互可达的。

也就是说,在一个强联通分量内的学校可以当作一个学校!

那么第一问我们所求的就是强连通分量重入度为零的点

而第二问因为两个强连通合并必然是出度为0的连接入度为0的点,所以要解决掉入度为0,和出度为0的点,所以答案是这两个的最大值(点指缩点)。

利用scc[i]=scc_cnt 来记录i这个点属于scc_cnt这个连通分量

总代码如下

#include <iostream>

#include <cstdio>

#include <cstring>

#include <stack>

using namespace std;

#define N 105

int first[N],scc[N],dfn[N],low[N],degreeIn[N],degreeOut[N],k,n,tmpdfn,scc_cnt;

stack<int> q;

struct Path{

    int y,next;

}path[100005];

void init()

{

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

    memset(dfn,0,sizeof(dfn));

    memset(degreeIn,0,sizeof(degreeIn));

    memset(degreeOut,0,sizeof(degreeOut));

    memset(scc,0,sizeof(scc));

    scc_cnt=0,tmpdfn=0,k=0;

}

void add(int x,int y)

{

    path[k].y=y,path[k].next=first[x];

    first[x]=k;

    k++;

}

void dfs(int u)

{

    dfn[u]=low[u]=++tmpdfn;

    q.push(u);

    for(int i=first[u];i!=-1;i=path[i].next){

        int v=path[i].y;

        if(!dfn[v]){

            dfs(v);

            low[u]=min(low[v],low[u]);

        }

        else if(!scc[v]) low[u]=min(low[u],dfn[v]);

    }

    if(low[u]==dfn[u]){

        scc_cnt++;

        for(;;){

            int v=q.top(); q.pop();

            scc[v]=scc_cnt;

            if(u==v) break;

        }

    }

}

void get_scc()

{

    while(!q.empty()) q.pop();

    for(int i=1;i<=n;i++)

        if(!dfn[i]) dfs(i);

    //cout<<"OK"<<endl;

    for(int i=1;i<=n;i++){

        for(int j=first[i];j!=-1;j=path[j].next){

            int v=path[j].y;

            //cout<<v<<endl;

            if(scc[i]!=scc[v]){

                degreeOut[scc[i]]++;

                degreeIn[scc[v]]++;

            }

        }

    }

}

int main()

{

    int i,a;

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

        int ans1=0,ans2=0;

        init();

        for(i=1;i<=n;i++){

            while(scanf("%d",&a) && a) add(i,a);

        }

        get_scc();

        //for(int i=1;i<=scc_cnt;i++) cout<<degreeIn[i]<<endl;

        //cout<<scc_cnt<<endl;

        for(int i=1;i<=scc_cnt;i++){

            if(!degreeOut[i]) ans1++;

            if(!degreeIn[i]) ans2++;

        }

        ans1=max(ans1,ans2);

        //cout<<"Á¬Í¨·ÖÁ¿£º"<<cnt<<endl;

        if(scc_cnt>1){

            printf("%d\n",ans2);

            printf("%d\n",ans1);

        }

        else printf("1\n0\n");

    }

    return 0;

}

 

你可能感兴趣的:(poj)