消息扩散--tarjan缩点
1.tarjan缩点,将问题简化成多个强连通分量的联通,其中找入度为0的
充分性:不找,那么这些就没有信息收到
必要性:找大于0的,那么连接他们的必定比他们更好,那就只有入度为0的了
2.板子理解不宜,多看
3.例题:炸铁路
受欢迎的 牛
刻录光盘
https://www.luogu.com.cn/problem/P2002
#include<bits/stdc++.h>
using namespace std;
#define N 100011
typedef long long ll;
typedef pair<ll,int> pii;
int n,m;
vector<int> mp[N];
int cnt,c;
int in[N];
int low[N],dfn[N];
int ne[N];
stack<int> st;
void tarjan(int u)
{low[u]=dfn[u]=++cnt;st.push(u);for(int v:mp[u]){if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else{if(!ne[v])///现在v还没有归到联通分量 ///先记住 {low[u]=min(low[u],low[v]);}}}if(low[u]==dfn[u]){ne[u]=++c;///第c个联通分量 while(st.top()!=u)///一定要这样写 {int v=st.top();ne[v]=c;st.pop();}st.pop();}
}
ll an;
int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=0;i<m;i++){int x,y;cin>>x>>y;if(x!=y)mp[x].push_back(y);} for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i);}for(int i=1;i<=n;i++){for(int v:mp[i]){if(ne[i]!=ne[v]){in[ne[v]]++;///统计缩完之后的点 }}}for(int i=1;i<=c;i++)///遍历缩完之后的强连通分量 {if(!in[i]) an++;}cout<<an;return 0;
}