P2002 消息扩散(缩点)

P2002 消息扩散

题目背景

本场比赛第一题,给个简单的吧,这 100 分先拿着。

题目描述

\(n\) 个城市,中间有单向道路连接,消息会沿着道路扩散,现在给出 \(n\) 个城市及其之间的道路,问至少需要在几个城市发布消息才能让这所有 \(n\) 个城市都得到消息。

输入格式

第一行两个整数 \(n, m\),表示 \(n\) 个城市,\(m\) 条单向道路。

以下 \(m\) 行,每行两个整数 \(b, e\) 表示有一条从 \(b\)\(e\) 的道路,道路可以重复或存在自环。

输出格式

一行一个整数,表示至少要在几个城市中发布消息。

输入输出样例 #1

输入 #1

5 4
1 2
2 1
2 3
5 1

输出 #1

2

说明/提示

【样例解释 #1】

样例中在 \(4, 5\) 号城市中发布消息。

【数据范围】

对于 \(20 \%\) 的数据,\(n \le 200\)
对于 \(40 \%\) 的数据,\(n \le 2000\)
对于 \(100 \%\) 的数据,\(1 \le n \le {10}^5\)\(1 \le m \le 5 \times {10}^5\)
这道题也一样,只需要统计入度为零的连通分量,因为如果他的入度为零,说明没有人可以把消息传给它,它必须自己获得消息,反之如果他的入度不为零,说明,消息可以从其它分量传给他,他自己就不用获得消息

#include<iostream>
#include<stack>
#include<set>
#define int long long
using namespace std;
const int N=1e5+5;
int n,m,b,e;
set<int>v[N];
stack<int>s;
int low[N],dfsn[N],vis[N],scc[N],inc[N],outc[N];
int t=0,cnt=0,ans=0;
void dfs(int x){
    low[x]=dfsn[x]=++t;
    vis[x]=1,s.push(x);
    for(int y:v[x]){
        if(!dfsn[y]){
            dfs(y);
            low[x]=min(low[x],low[y]);
        }
        else if(vis[y])low[x]=min(low[x],dfsn[y]);
    }
    if(low[x]==dfsn[x]){
        cnt++;
        while(s.top()!=x){
            vis[s.top()]=0;
            scc[s.top()]=cnt;
            s.pop();
        }
        vis[s.top()]=0;
            scc[s.top()]=cnt;
            s.pop();
    }
}
signed main(){
    cin>>n>>m;
    while(m--){
        cin>>b>>e;
        if(b!=e)v[b].insert(e);
    }
    for(int i=1;i<=n;i++)if(!dfsn[i])dfs(i);
    for(int x=1;x<=n;x++){
        for(int y:v[x]){
            if(scc[x]!=scc[y]){
                outc[scc[x]]++;
                inc[scc[y]]++;
            }
        }
    }
    for(int i=1;i<=cnt;i++)if(!inc[i])ans++;
    cout<<ans;
    return 0;
}
posted @ 2025-03-15 22:47  郭轩均  阅读(5)  评论(0)    收藏  举报