Network of Schools POJ - 1236 tarjan强连通分量

19 篇文章 0 订阅
19 篇文章 0 订阅

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;//stack
int cnt;//dot
int n;//point
int tm;//time
void 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值