Mr. Kitayuta‘s Technology CodeForces - 505D(並查集+拓撲排序或dfs找環) 題解

韜光養晦_發表於2020-12-15

題目 
Shuseki Kingdom is the world’s leading nation for innovation and technology. There are n cities in the kingdom, numbered from 1 to n.

Thanks to Mr. Kitayuta’s research, it has finally become possible to construct teleportation pipes between two cities. A teleportation pipe will connect two cities unidirectionally, that is, a teleportation pipe from city x to city y cannot be used to travel from city y to city x. The transportation within each city is extremely developed, therefore if a pipe from city x to city y and a pipe from city y to city z are both constructed, people will be able to travel from city x to city z instantly.

Mr. Kitayuta is also involved in national politics. He considers that the transportation between the m pairs of city (ai, bi) (1 ≤ i ≤ m) is important. He is planning to construct teleportation pipes so that for each important pair (ai, bi), it will be possible to travel from city ai to city bi by using one or more teleportation pipes (but not necessarily from city bi to city ai). Find the minimum number of teleportation pipes that need to be constructed. So far, no teleportation pipe has been constructed, and there is no other effective transportation between cities.

Input 
The first line contains two space-separated integers n and m (2 ≤ n ≤ 105, 1 ≤ m ≤ 105), denoting the number of the cities in Shuseki Kingdom and the number of the important pairs, respectively.

The following m lines describe the important pairs. The i-th of them (1 ≤ i ≤ m) contains two space-separated integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi), denoting that it must be possible to travel from city ai to city bi by using one or more teleportation pipes (but not necessarily from city bi to city ai). It is guaranteed that all pairs (ai, bi) are distinct.

Output 
Print the minimum required number of teleportation pipes to fulfill Mr. Kitayuta’s purpose.

Example 
Input 
4 5 
1 2 
1 3 
1 4 
2 3 
2 4 
Output 

Input 
4 6 
1 2 
1 4 
2 3 
2 4 
3 2 
3 4 
Output 
4


題目大意就是城市之間可以修單向的瞬時傳送門,現在給出需求(需要那個城市可以到達娜個城市),問你最少需要修多少個傳送通道,首先可以知道,對於需求構成的一個聯通塊,若連通塊有環,只需要把連通塊裡的點修出一個單項環,任意點就可以互相達到了,若無環,只需要修n-1條路就可以滿足需求了。 
所以我們只需要用並查集找出所有的連通塊,然後對每個連通塊判斷環就行,我用了拓撲排序和dfs找環兩種方法來做。 
首先是拓撲排序,拓撲排序本身是針對無環有向圖的,通過不斷把沒有入度的點入隊來實現,而若有環,則環上的點始終無法入隊,最後處理完它們的入度也不會變成零,這樣就很容易找出環了。 
dfs找環的方法就是對點賦予狀態,0表示沒訪問過,1表示這個點及其相連的連通塊都已經訪問過了,-1則表示這個點正在對其dfs深搜訪問,若一個點狀態為-1又被再一次訪問到,那麼這肯定就是一個環了。

 

1.拓撲排序

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<algorithm>
#include<queue>
#include<set>
#include<stack>
using namespace std;
int f[100005];
int n, m;
vector<int > e[100005];
queue<int> que;
int F(int x){
    if (f[x] == x)return x;
    return f[x] = F(f[x]); }
bool H[100005];
int lt[100005];
bool vis[100005];
int deg[100005];

void func(){
    while (!que.empty()){
        int cnt = que.front();
        que.pop();
        for (int i = 0; i < e[cnt].size(); i++){
            deg[e[cnt][i]]--;
            if (deg[e[cnt][i]] == 0)que.push(e[cnt][i]);
        }
    }
}

int main(){
    int x, y;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)f[i] = i;
    for (int i = 0; i < m; i++){
        scanf("%d%d", &x, &y);
        e[x].push_back(y);
        deg[y]++;
        f[F(x)] = F(y);
    }
    for (int i = 1; i <= n; i++){
        lt[F(i)]++;
        if (deg[i] == 0)que.push(i);
    }
    func();
    int ans = 0;
    for (int i = 1; i <= n; i++){
        if (deg[i] != 0)H[F(i)] = 1;
    }
    for (int i = 1; i <= n; i++){
        if (f[i] == i){
            if (H[i])ans += lt[i];
            else{ ans += lt[i] - 1; }
        }
    }
    printf("%d", ans);
    return 0;
}

 

2.DFS找環

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<string>
#include<vector>
#include<algorithm>
#include<queue>
#include<set>
#include<stack>
using namespace std;
int f[100005];
int n, m;
vector<int > e[100005];
queue<int> que;
int F(int x){
    if (f[x] == x)return x;
    return f[x] = F(f[x]); }
bool H[100005];
int lt[100005];
bool vis[100005];
int c[100005];

void dfs(int cnt){
    c[cnt] = -1;
    for (int i = 0; i < e[cnt].size(); i++){
        int cur = e[cnt][i];
        if (c[cur] == -1){ H[F(cur)] = 1; break; }
        else if (c[cur] == 0){ dfs(cur); }
    }
    c[cnt] = 1;
}

int main(){
    int x, y;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)f[i] = i;
    for (int i = 0; i < m; i++){
        scanf("%d%d", &x, &y);
        e[x].push_back(y);
        //deg[y]++;
        f[F(x)] = F(y);
    }
    for (int i = 1; i <= n; i++){
        lt[F(i)]++;
        if (c[i] == 0)dfs(i);
        //if (deg[i] == 0)que.push(i);
    }
//  func();
    int ans = 0;
    for (int i = 1; i <= n; i++){
        if (f[i] == i){
            if (H[i])ans += lt[i];
            else{ ans += lt[i] - 1; }
        }
    }
    printf("%d", ans);
    return 0;
}

 

相關文章