Berland有n个城市和m条路。 每条路连接两个城市, 所有路都是单向的。

为了能从首都到达所有城市,需要建造的最少的新道路的数量是多少?

新建的道路也是单向的。

首先我们知道这是一道问是否联通的题,所以确定算法是tarjan求强连通分量,我们知道,如果问题是求加最少的边使图变为连通图的话,加的边数是缩点后入度为0的点和出度为0的点取max——因为因为强联通分量保证的是从每一个点出发都可以到达其他任意点,所以不可能有一个点他的入度或者出度为0,假设min(入度为0,出度为0)=x,max(入度为0,出度为0)=y,那么有x条边是从出度为0的点指向入度为0的点,剩下y-x条边只需要保证从出度为0的点出或者从入度为0的点入就可以了。但是现在问的不是这个问题,而是要求从一个点出发,可以到达其他任何一个点,问最少加的边数,首先是缩点,但是我们不需要保证图是联通的了,也就是除了s所在的强联通分量,其他点都要有至少一个入度,所以我们统计入度为零的点的个数就可以了。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=5e4+5;
int n,m,s;
int x,y;
int tot;
struct zhw{
    int to,last;
}tu[maxn];
int head[maxn]; 
void add(int x,int y)
{
    tot++,tu[tot].last=head[x],head[x]=tot,
    tu[tot].to=y;
}
int dfn[maxn],low[maxn],tim;
bool vis[maxn];
int stack[maxn],top;
int cnt,sum[maxn],belong[maxn]; 
void tarjan(int x)
{
    low[x]=dfn[x]=++tim;
    vis[x]=1;stack[++top]=x;
    for(int i=head[x];i;i=tu[i].last)
    {
        if(!dfn[tu[i].to])tarjan(tu[i].to),low[x]=min(low[x],low[tu[i].to]);
        else if(vis[tu[i].to])low[x]=min(low[x],low[tu[i].to]); 
    }
    if(low[x]==dfn[x])
    {
        cnt++;
        while(stack[top+1]!=x)
        {
            int tmp=stack[top];top--;
            belong[tmp]=cnt,vis[tmp]=0;sum[cnt]++;
        }
    }
}
int in[maxn]; 
int main()
{

    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;++i)
        if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;++i)
    {
        for(int j=head[i];j;j=tu[j].last)
        {
            if(belong[i]!=belong[tu[j].to])
                in[belong[tu[j].to]]++;
        }
    }
    in[belong[s]]=1;//保证s所在的强联通分量不需要统计
    int ans1=0,ans2=0,ans;
    for(int i=1;i<=cnt;++i)
    {
        if(in[i]==0)ans1++;
    }
    //if(cnt==1)ans1=0;
    printf("%d\n",ans1);
    return 0;
}