505D Mr. Kitayuta's Technology(并查集+拓扑排序)

D. 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 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.

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

题意:给你n个点和m条单向边,边有传递性,即 a->b,b->c 可实现 a->c, 问满足输入的m条边的实现,最少需要修几条单向边。

 

思路:最方便的是将n个顶点连成环,但这不是最优解,对于强联通分量,是得连成环,但对于弱联通分量我们可以拓扑排序得到一个线性排序,只用n-1的边就行,总之,也就说

对于每个连通分量,如果其中有环,无论环的个数,最多就把整个连通分量弄成环,假如连通分量没环,就拓扑排序,用n-1条边(因为存在有向环是不存在拓扑排序的),这里用到

了并查集,十分巧妙的解决了一个连通分量有多个环难计数的难点,其实这里还是可以用tarjan算法,但我掌握的不熟,以后熟练了可以试下。

 

小知识点(知道的同学忽略= =):我这里的siz[N]数组没特地初始化,原因:C语言规定,普通数组没有赋初值,默认的数组元素值是随机数,不是0。
如果在定义数组时,数据类型前面加上关键字static,数组变成了静态数组;或者把数组定义在函数的外面,成为全局变量数组,这时数组元素的值自动赋值为0。

 

代码:
#include
#include
#include
#include
#include
#define N 100100
using namespace std;//62 ms  9800 KB

int f[N],ans[N],vis[N],cyc[N],siz[N];
vectore[N];

int find(int x)
{
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}
void uni(int x,int y)
{
    if(find(x)==find(y)) return;
    siz[find(y)]+=siz[find(x)];//算每个集合的个数
    f[find(x)]=find(y);
}
void dfs(int u)
{
    vis[u]=1;//某个连通分量正在访问
    for(int i=0;i     {
        int v=e[u][i];
        if(!vis[v])
            dfs(v);
        if(vis[v]==1)//在某个连通分量遇到了环,在集合上做标记
            cyc[find(v)]=1;
    }
    vis[u]=2;//某个连通分量已经访问过了
}
int main()
{
    int x,y,n,m,ans=0;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        f[i]=i,siz[i]=1;
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        uni(x,y);
    }
    for(int i=1; i<=n; i++)
        if(!vis[i])dfs(i);
    for(int i=1; i<=n; i++)
    {
        if(find(i)==i)
            ans+=siz[i]-1;
        ans+=cyc[i];
    }
    printf("%d\n",ans);
}

 

你可能感兴趣的:(codeforces)