• Codeforces 999E(强连通分量缩点)


    传送门

    题面:

    E. Reachability from the Capital

    time limit per test

    2 seconds

    memory limit per test

    256 megabytes

    input

    standard input

    output

    standard output

    There are nn cities and mm roads in Berland. Each road connects a pair of cities. The roads in Berland are one-way.

    What is the minimum number of new roads that need to be built to make all the cities reachable from the capital?

    New roads will also be one-way.

    Input

    The first line of input consists of three integers nn, mm and ss (1≤n≤5000,0≤m≤5000,1≤s≤n1≤n≤5000,0≤m≤5000,1≤s≤n) — the number of cities, the number of roads and the index of the capital. Cities are indexed from 11 to nn.

    The following mm lines contain roads: road ii is given as a pair of cities uiui, vivi (1≤ui,vi≤n1≤ui,vi≤n, ui≠viui≠vi). For each pair of cities (u,v)(u,v), there can be at most one road from uu to vv. Roads in opposite directions between a pair of cities are allowed (i.e. from uu to vv and from vv to uu).

    Output

    Print one integer — the minimum number of extra roads needed to make all the cities reachable from city ss. If all the cities are already reachable from ss, print 0.

    Examples

    input

    Copy

    9 9 1
    1 2
    1 3
    2 3
    1 5
    5 6
    6 1
    1 8
    9 8
    7 1
    

    output

    Copy

    3
    

    input

    Copy

    5 4 5
    1 2
    2 3
    3 4
    4 1
    

    output

    Copy

    1
    

    Note

    The first example is illustrated by the following:

    For example, you can add roads (6,46,4), (7,97,9), (1,71,7) to make all the cities reachable from s=1s=1.

    The second example is illustrated by the following:

    In this example, you can add any one of the roads (5,15,1), (5,25,2), (5,35,3), (5,45,4) to make all the cities reachable from s=5s=5.

    题目描述:

        给你n个点,m条边,以及一个初始点s,问你至少还需要增加多少条边,使得初始点s与剩下其他的所有点都连通。

    题目分析:

        因为要讨论连通性,而题目所要讨论的有向图,因此我们可以首先统计强连通分量,并通过Tarjin缩点,并重新构图。将图重构之后,我们会发现,倘若除了s结点所在的连通分量,如果其他连通分量所构成的新点的入度为0,则使这个连通分量与s连通的最优的方案是将这个点与s结点相连。

        因此,对于这个问题,我们只需要在缩点之后统计一下入读为0的新点即是答案。

    代码:

    #include <bits/stdc++.h>
    #define maxn 200005
    using namespace std;
    struct edge{
        int next,to;
    }q[maxn];
    int head[maxn],dfn[maxn],low[maxn],cnt,tot;
    int vis[maxn],belong[maxn],index,belong_num[maxn],num_index;
    int indegree[maxn],outdegree[maxn];
    void add_edge(int from,int to){
        q[cnt].next=head[from];
        q[cnt].to=to;
        head[from]=cnt++;
    }
    void init(){//初始化
        memset(vis,0,sizeof(vis));
        memset(dfn,0,sizeof(dfn));
        memset(head,-1,sizeof(head));
        memset(low,0,sizeof(low));
        memset(belong_num,0,sizeof(belong_num));//在某个连通块中有多少个结点
        memset(indegree,0,sizeof(indegree));//新图的入度
        memset(outdegree,0,sizeof(outdegree));
        index=num_index=cnt=tot=0;
    }
    stack<int>st;
    void tarjin(int x){//Tarjin的主体
        dfn[x]=low[x]=++tot;
        vis[x]=1;
        st.push(x);
        for(int i=head[x];i!=-1;i=q[i].next){
            edge e=q[i];
            if(!dfn[e.to]){
                tarjin(e.to);
                low[x]=min(low[e.to],low[x]);
            }
            else if(vis[e.to]==1){
                low[x]=min(low[x],dfn[e.to]);
            }
        }
        if(dfn[x]==low[x]){
            int v;
            index=index+1;
            do{
                v=st.top();
                st.pop();
                belong[v]=index;
                belong_num[index]++;
                vis[v]=0;
            }while(v!=x);
        }
    }
    void solve(int n,int m,int root){
        for(int i=1;i<=n;i++){//对图进行Tarjin
            if(!dfn[i]){
                tarjin(i);
            }
        }
        //如果连通分量只有一个,则直接输出0
        if(index==1){
            puts("0");
            return ;
        }
        indegree[belong[root]]=1;//确保初始点root所在的连通分量入度不为0
        
        for(int i=1;i<=n;i++){//重构图的过程
            for(int j=head[i];j!=-1;j=q[j].next){
                edge e=q[j];
                if(belong[i]==belong[e.to]) continue;
                indegree[belong[e.to]]++;
                outdegree[belong[i]]++;
            }
        }
        int cnt=0;//统计入度为0的点
        for(int i=1;i<=index;i++){
            if(indegree[i]==0){
                cnt++;
            }
        }
        cout<<cnt<<endl;
    }
    int main()
    {
        int n,m,s;
        cin>>n>>m>>s;
        init();
        for(int i=1;i<=m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            add_edge(a,b);
        }
        solve(n,m,s);
        return 0;
    }
    
  • 相关阅读:
    JDBC
    两道关于回溯法,分支限界法的算法题
    旅行售货员问题
    jdbc学习
    mysql简单练习
    取会邮件客户端中的密码
    触发器的使用
    事务的数据一致性测试
    读取其他软件listview控件的内容
    sqlserver2008 ,只能选C盘目录,不能选其它盘目录
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007272.html
Copyright © 2020-2023  润新知