poj 1236

poj 1236

强连通分量 tarjan。第一题,。。

题目:
传送

题目大意:有N个学校,从每个学校都能从一个单向网络到另外一个学校,两个问题
1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
2:至少需要添加几条边,使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

解题思路:

求所有连通分量,然后缩点,构成一个有向无环的图,有多少个入度为0的点就是第一问的答案。
第二问呢,很神奇~
现在图上有n个入度为0的点,编号为0 1 2 .。。N,有m个出度为0的点。
把所有入度为0的点可达的出度0点,添加一条出边。需要n条边。
如果 n>m
那么就是n;否则再加m-n。一共是m
所一第二问是max{m,n}

代码:

zrtorz大神神神。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,t,dfn[110],low[110],num,strong[110];
int ru[110],chu[110];
bool v[110];
int stack[110],p;
int next[10010],ver[10010],head[10010],tot;
struct edge{int st,end;
}a[10010];
void add(int x,int y)
{
    tot++;
    ver[tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}
void tarjan(int x)
{
    int i;
    dfn[x]=low[x]=++num;
    stack[++p]=x;v[x]=1;
    for(i=head[x];i;i=next[i])
    {
        if(!dfn[ver[i]])
        {
            tarjan(ver[i]);
            low[x]=min(low[x],low[ver[i]]);
        }
        else if(v[ver[i]])
            low[x]=min(low[x],low[ver[i]]);
    }
    if(low[x]==dfn[x])
    {
        int y;
        ++t;
        do
        {
            y=stack[p--];
            v[y]=0;
            strong[y]=t;
        }
        while(y!=x);
    }
}
int main()
{
    int i,j,k,ans1=0,ans2=0;
    cin>>n;
    for(i=1;i<=n;i++)
        while(scanf("%d",&j)!=EOF&&j!=0)
            add(i,j),a[tot].st=i,a[tot].end=j;
    for(i=1;i<=n;i++)
    {
        if(!dfn[i])
            tarjan(i);      
    }
    for(i=1;i<=tot;i++)
    {
        if(strong[a[i].st]==strong[a[i].end])
            continue;
        chu[strong[a[i].st]]++;
        ru[strong[a[i].end]]++;
    }
    for(i=1;i<=t;i++)
    {
        if(!ru[i])
            ans1++;
    }
    cout<<ans1<<endl;
    if(t==1)
    {
        cout<<0;
        return 0;
    }
    for(i=1;i<=t;i++)
    {
        if(!chu[i])
            ans2++;
    }
    ans2=max(ans1,ans2);
    cout<<ans2;
    return 0;
}

你可能感兴趣的:(poj)