POJ - 1236 Network of Schools (Tarjan)

题目大意:

N(2<N<100)各学校之间有单向的网络,每个学校可以通过单向网络向周边的学校传输文件,问题1:最少向几个学校投放文件使得所有的学校都能得到文件。2,至少需要添加几条有向边使得从任意一个学校开始都能传到其他学校。

分析:

我们可以先进行缩点求出有向无环图,明显第一个问题就是求解入度为0的点的数目。然后我们考虑第二个问题。这是一个连通图。如果我们有些点没有入点,有些点没出点。那我们如果想办法将入点和一些出点相连,就能保证最后会成为很多圆相连。这样子答案就是没有入边的点和没有出边的点的最大值。
 

#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>

using namespace std;

const int maxn=110;

struct node{
    int to,nxt;
}edge[5555];

int head[maxn],tot;
int low[maxn],dfn[maxn],sta[maxn],belg[maxn],out[maxn],in[maxn];
int index,top;
int scc;
bool instack[maxn];

void addedge(int u,int v){
    edge[tot].to=v;
    edge[tot].nxt=head[u];
    head[u]=tot++;
}

void Tarjan(int u){
    int v;
    low[u]=dfn[u]=++index;
    sta[top++]=u;
    instack[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        v=edge[i].to;
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        if(instack[v]&&low[u]>dfn[v]){
            low[u]=dfn[v];
        }
    }
    if(low[u]==dfn[u]){
        scc++;
        do{
            v=sta[--top];
            instack[v]=0;
            belg[v]=scc;
        }while(v!=u);
    }
}

void init(){
    tot=index=scc=top=0;
    memset(dfn,0,sizeof dfn);
    memset(instack,0,sizeof instack);
    memset(low,0,sizeof low);
    memset(head,-1,sizeof head);
    memset(out,0,sizeof out);
    memset(in,0,sizeof in);
}

int main(){
    int n;
    while(~scanf("%d",&n)){
        init();
        for(int i=1;i<=n;i++){
            int x;
            while(scanf("%d",&x),x){
                addedge(i,x);
            }
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]){
                Tarjan(i);
            }
        }
        if(scc==1){
            printf("1\n0\n");
            continue;
        }
        for(int i=1;i<=n;i++){
            for(int j=head[i];~j;j=edge[j].nxt){
                int u=i,v=edge[j].to;
                if(belg[u]!=belg[v]){
                    in[belg[v]]++;
                    out[belg[u]]++;
                }
            }
        }
        int res1=0,res2=0;
        for(int i=1;i<=scc;i++){
            if(!in[i]) res1++;
            if(!out[i]) res2++;
        }
        printf("%d\n%d\n",res1,max(res1,res2));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40679299/article/details/84496047