POJ 1236 Tarjan算法

来源:互联网 发布:js小球碰撞 编辑:程序博客网 时间:2024/04/30 01:11

这道题认真想了想。。

题目大意:有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\n0");    else printf("%d\n%d",ans,max(ans,anss));}

这里写图片描述

1 0
原创粉丝点击