1. 程式人生 > >Codeforces 999E(強連通分量縮點)

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;
}