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;
}