zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    sql语句添加查询字段
    SqlServer Case when then用法总结
    单例与多线程
    HttpSession详解
    范式
    SQL语句中的Having子句与where子句
    HTTP无状态
    字节流与字符流的区别
    选择排序
    ReentrantLock VS synchronized
  • 原文地址:https://www.cnblogs.com/zzrblogs/p/10458538.html
Copyright © 2011-2022 走看看