CF999E Reachability from the Capital来自首都的可达性

题目大意:

有n个节点m条边,边都是单向的,请你添加最少的边使得起点s到其他与其他每一个点之间都能互相到达

这题一看就是一个缩点啊

其实对于原有的m条边相连的一些点,如果之前他们已经形成了强连通分量(scc),那么它们之前就可以相互到达(不用修路),对于这些点我们可以把它们“缩”成一个“点”,这其实就是Tarjian缩点的思想

其实luogu里还有很多缩点的模板题,自己去找找吧,都不难的

那么如果你会了缩点,这个题只要缩完点之后统计一下入度为0的点就行了(让强连通分量之间连边)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
const int inf=1e9+7;
inline int read()
{
    int p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
    return f*p;}
const int maxn=5007;
const int maxm=5007;
struct Edge
{
    int next,from,to;
}p[maxm];
struct point
{
    int low,dnf,vis,fa,in;
}A[maxn];
int n,m,cnt,sum_scc,tot,S;
int Stack[maxn],top,ans,head[maxm];
inline void add_edge(int x,int y)//加边
{
    cnt++;
    p[cnt].from=head[x];
    head[x]=cnt;
    p[cnt].next=x;
    p[cnt].to=y;
}
inline void Tarjian(int x)//Tarjian缩点
{
    A[x].dnf=A[x].low=++tot;
    A[x].vis=1,Stack[++top]=x;
    for(int i=head[x];i;i=p[i].from)
        {
            int y=p[i].to;
            if(!A[y].dnf)
                Tarjian(y),A[x].low=min(A[x].low,A[y].low);
            else if(A[y].vis)
                    A[x].low=min(A[x].low,A[y].dnf);
        }
    if(A[x].dnf==A[x].low)
        {
            int y;
            sum_scc++;
            while(y=Stack[top--])
                {
                    A[y].vis=0;
                    A[y].fa=sum_scc;
                    if(x==y)break;
                }
        }
}
int main()
{
    n=read(),m=read(),S=read();
    for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            add_edge(x,y);
        }
    for(int i=1;i<=n;i++)
        if(!A[i].dnf)Tarjian(i);
    for(int i=1;i<=m;i++)//统计入度
        {
            int x=A[p[i].next].fa,y=A[p[i].to].fa;
            if(x!=y)A[y].in++;
        }
    for(int i=1;i<=sum_scc;i++)
        //没有入度的scc个数++
        if(!A[i].in)ans++;
    if(!A[A[S].fa].in)ans--;
    //特判,起点所在的scc如果没有入度那么答案-1
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zzrblogs/p/10458538.html