Network of Schools POJ

来源:互联网 发布:马云否认淘宝是日本的 编辑:程序博客网 时间:2024/05/29 13:17

tarjan强连通分量

题意
N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
思路
也就是:
— 给定一个有向图,求:
1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
解法
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
4.在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
设ans1入度为零的定点数,ans2出度为零的顶点数
加边条数是max(ans1,ans2);

此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;
代码

/* * Author       :  Echo * Email        :  1666424499@qq.com   * Description  :    * Created Time :  2017/10/10 19:25:26 * Last Modify  :  2017/10/15 16:03:40 * File Name    :  \yanga11ang\write.cpp */#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <queue>using namespace std;const int maxn=110;const int maxm=1e4+100;const int INF=1e9;struct edge {    int to,next;}an[maxm];int head[maxn];int dfn[maxn]; //入栈时间戳int ins[maxn]; //是否入栈int low[maxn]; //最早发现时间int stk[maxn]; //手工栈int dot[maxn]; //缩点int ind[maxn]; //入度int out[maxn]; //出度int m=0;//edge int top;//stackint cnt;//dotint n;//pointint tm;//timevoid addedge(int u,int v){    an[++m].to=v;    an[m].next=head[u];    head[u]=m;}void tarjan(int u){    dfn[u]=low[u]=++tm;    stk[++top]=u;    ins[u]=1;    for(int i=head[u];i!=-1;i=an[i].next){        int v=an[i].to;        if(dfn[v]==0){            tarjan(v);            if(low[u]>low[v]) low[u]=low[v];        }         else if(ins[v]&&low[u]>low[v]){            low[u]=low[v];        }    }    if(low[u]!=dfn[u]) return;    int v=stk[top--];    ins[v]=0;    dot[v]=++cnt;    while(u!=v){        v=stk[top--];        ins[v]=0;        dot[v]=cnt;    }}int main(){    cin>>n;    m=top=cnt=tm=0;    for(int i=1;i<=n;i++){        dfn[i]=ins[i]=ind[i]=out[i]=0;        head[i]=-1;    }    for(int i=1;i<=n;i++){        int j;        while(scanf("%d",&j)&&j){            addedge(i,j);        }    }    for(int i=1;i<=n;i++){        if(dfn[i]) continue;         tarjan(i);    }    for(int u=1;u<=n;u++){        for(int i=head[u];i!=-1;i=an[i].next){            int v=an[i].to;            if(dot[u]==dot[v])continue;            out[dot[u]]++;            ind[dot[v]]++;        }    }    int ans1=0,ans2=0;    for(int i=1;i<=cnt;i++){        if(ind[i]==0) ans1++;        if(out[i]==0) ans2++;    }    if(cnt==1)printf("1\n0\n");    else printf("%d\n%d\n",ans1,ans1>ans2? ans1:ans2);    return 0;}
原创粉丝点击