POJ 1236 Tarjan算法

这道题认真想了想。。

题目大意:有N个学校,从每个学校都能从一个单向网络到另外一个学校,两个问题
1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
2:至少需要添加几条边,使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
解题思路:
首先找连通分量,然后看连通分量的入度为0点的总数,出度为0点的总数,那么问要向多少学校发放软件,就是入度为零的个数,这样才能保证所有点能够找到
然后第二问添加多少条边可以得到使整个图达到一个强连通分量,答案是入度为0的个数和出度为0的个数中最大的
那个,为什么会这样呢,经过我同学的讨论,将这个图的所有子树找出来,然后将一棵子树的叶子结点(出度为0)连到另外一棵子树的根结点上(入度为0),这样将所有的叶子结点和根节点全部消掉之后,就可以得到一整个强连通分量,看最少多少条边,这样就是看叶子结点和根节点哪个多,即出度为0和入度为0哪个多
】(转自http://blog.csdn.net/wangjian8006
顺便看了看zrt的题解。。

#include <stack>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector <int> v[105];
stack<int> stk;
int low[105],dfn[105],p[105],in[105],out[105],ans=0,jy,cnt=0,N,t=0,anss=0;
bool vis[105];
void tarjan(int x)
{
    low[x]=dfn[x]=++cnt,vis[x]=1,stk.push(x);
    for(int i=0;i<v[x].size();i++)
        if(!dfn[v[x][i]]) tarjan(v[x][i]),low[x]=min(low[x],low[v[x][i]]);
        else if(vis[v[x][i]]) low[x]=min(low[x],dfn[v[x][i]]); 
    if(dfn[x]==low[x]){
        int y;t++;
        do y=stk.top(),stk.pop(),vis[y]=0,p[y]=t;while(y!=x);
    }
}
int main()
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
        while(scanf("%d",&jy)&&jy)
            v[i].push_back(jy);
    for(int i=1;i<=N;i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=N;i++)
        for(int j=0;j<v[i].size();j++)
            if(p[i]!=p[v[i][j]])
                in[p[v[i][j]]]++,out[p[i]]++;
    for(int i=1;i<=t;i++){
        if(!in[i])ans++;
        if(!out[i])anss++;
    }
    if(t==1)printf("1
0");
    else printf("%d
%d",ans,max(ans,anss));
}

这里写图片描述

原文地址:https://www.cnblogs.com/SiriusRen/p/6532486.html