Codeforces Round #286 (Div. 1) B. Mr. Kitayuta's Technology 连通分量 拓扑排序

B. Mr. Kitayuta's Technology
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Shuseki Kingdom is the world's leading nation for innovation and technology. There aren cities in the kingdom, numbered from1 ton.

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 cityx to city y cannot be used to travel from cityy to cityx. The transportation within each city is extremely developed, therefore if a pipe from cityx to cityy and a pipe from cityy to cityz are both constructed, people will be able to travel from cityx to cityz instantly.

Mr. Kitayuta is also involved in national politics. He considers that the transportation between them 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 cityai to citybi by using one or more teleportation pipes (but not necessarily from citybi to cityai). 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 andm (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. Thei-th of them (1 ≤ i ≤ m) contains two space-separated integersai andbi (1 ≤ ai, bi ≤ n, ai ≠ bi), denoting that it must be possible to travel from city ai to citybi by using one or more teleportation pipes (but not necessarily from citybi to cityai). 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.

Sample test(s)
Input
4 5
1 2
1 3
1 4
2 3
2 4
Output
3
Input
4 6
1 2
1 4
2 3
2 4
3 2
3 4
Output
4

  ai,bi表示ai能到达bi,要求满足这些条件的图最少用多少条边。

  所有有关联的点为一个连通分量,先用DFS划分出所有的连通分量。对于包含n个点的单个连通分量来说,如果它是一个有向无环图,那么用拓扑排序的顺序连起来边数为n-1,能满足条件,并且也是边数最少的,因为n个有关系的点至少也要n-1条边。如果有环的话,那么用n条边把这n个点连成一个环,两两可达。判断是不是有向无环图就用类似拓扑排序的方法。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
typedef long long LL;
using namespace std;

const int MAXN=100010;

int N,M,idx,belong[MAXN],deg[MAXN],cnt[MAXN];
vector<int> V[MAXN],G[MAXN],Component[MAXN];

void DFS(int u){
    belong[u]=idx;
    int len=V[u].size();
    for(int i=0;i<len;i++){
        int v=V[u][i];
        if(belong[v]==-1) DFS(v);
    }
}

bool DAG(int c){
    queue<int> q;
    int len=Component[c].size();
    for(int i=0;i<len;i++){
        int u=Component[c][i];
        if(!deg[u]) q.push(u);
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        int len2=G[u].size();
        for(int i=0;i<len2;i++){
            int v=G[u][i];
            deg[v]--;
            if(!deg[v]) q.push(v);
        }
    }
    for(int i=0;i<len;i++){
        int u=Component[c][i];
        if(deg[u]) return false;
    }
    return true;
}

int main(){
    freopen("in.txt","r",stdin);
    while(scanf("%d%d",&N,&M)!=EOF){
        int u,v;
        for(int i=0;i<=N;i++){
            V[i].clear();
            G[i].clear();
            Component[i].clear();
        }
        for(int i=0;i<M;i++){
            scanf("%d%d",&u,&v);
            deg[v]++;
            V[u].push_back(v);
            V[v].push_back(u);
            G[u].push_back(v);
        }
        idx=0;
        memset(belong,-1,sizeof(belong));
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=N;i++) if(belong[i]==-1){
            DFS(i);
            idx++;
        }
        int ans=0;
        for(int i=1;i<=N;i++){
            cnt[belong[i]]++;
            Component[belong[i]].push_back(i);
        }
        for(int i=0;i<idx;i++){
            if(DAG(i)) ans+=cnt[i]-1;
            else ans+=cnt[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值