嘘~ 正在从服务器偷取页面 . . .

模拟赛题讲解[2]


模拟赛题讲解[2]

来自 Roundgod 2022-07-25 noi.ac #2677

题目描述

给定一个有向图 $G=(V,E)$ ,其中顶点个数 $|V|=n$ ,边数 $|E|=m$ 。顶点编号为 $1−N$ ,边的编号为 $1−M$ ,第 $i$ 条边连接顶点 $a_i$ 和 $b_i$ 。

Makima会从图中的某个顶点出发并重复沿着某条有向边行走。你需要计算:存在多少个顶点 $v$ ,使得Makima可以从点 $v$ 出发无限地走下去?

输入格式

输入第一行包含 $2$ 个整数 $n,m$ ,分别表示图的顶点数和图的边数。

接下来 $m$ 行,每行包含两个整数 $a_i,b_i(1\le a_i,b_i\le n,a_i\ne b_i)$ ,表示第 $i$ 条边从顶点 $a_i$ 指向顶点 $b_i$ 。

输出格式

在一行中输出一个整数,表示满足条件的顶点个数。

输入1

5 5
1 2
2 3
3 4
4 2
4 5

输出1

4

输入2

3 2
1 2
2 1

输出2

2

数据范围

对于 $50\%$ 的数据,$1\le n\le 2000,~1\le m\le 10000$

对于 $100\%$ 的数据,$1\le n\le 2\times 10^5,~1\le m\le 2\times 10^5$

题解

这题还是比较简单的,赛时秒了

不难发现,如果一个结点出发可以走到一个环上

这个点、这个点到环的路径上的所有点以及所有能走到这个点的点 都是满足要求的点

显然问题就变成了:找到哪些结点是死路(走不到环上)

考虑建反图然后跑 $\text{topo}$ 排序。

可以认为这个过程是,倒着思考,从死路出发,看看它能祸害多少结点

好像这个题可以用 $\text{Tarjan}$ ,不过我这个不太熟,等熟练了再说吧。

时间复杂度 $O(n)$

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <random>
#include <queue>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(2e5+15)

int n,m,pos=1,head[N],in[N];
queue<int> q;
struct Edge{int u,v,next;} e[N];
void addEdge(int u,int v)
{
    e[++pos]={u,v,head[u]};
    head[u]=pos;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    read(n); read(m);
    for(int i=1,u,v; i<=m; i++)
    {
        read(u); read(v);
        addEdge(v,u); ++in[u];
    }
    int res=n;
    for(int i=1; i<=n; i++)
        if(!in[i]) q.push(i);
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        --res;
        for(int i=head[u]; i; i=e[i].next)
        {
            if(!(--in[e[i].v]))
                q.push(e[i].v);
        }
    }
    write(res);
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录