CF999E Solution
题解
可以发现,在一个强连通分量中,只要一个节点可以到达\(s\)节点,所有节点均可以到达。因此将强连通分量缩点,入度为0且不包含根节点的缩点个数即为答案。易证,入度不为0的缩点一定可以通过与它连接的缩点到达\(s\)节点。
AC题解
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
int fst[N],nxt[N],v[N],cnt;
int c[N],dfn[N],low[N],pos,sum,s;//c[i]:编号为i的节点所在强连通分量编号
bool ins[N],in[N];//in[i]:编号为i的强连通分量是(1)否(0)有入边
stack<int> st;
void add(int a,int b)
{
v[++cnt]=b;
nxt[cnt]=fst[a]; fst[a]=cnt;
}
void tarjan(int x)
{
dfn[x]=low[x]=++pos;
st.push(x); ins[x]=1;
for(int i=fst[x];i;i=nxt[i])
{
int y=v[i];
if(!dfn[y]) {tarjan(y); low[x]=min(low[x],low[y]);}
else if(ins[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
c[x]=++sum; ins[x]=0;
while(st.top()!=x)
{
int t=st.top(); st.pop();
c[t]=sum; ins[t]=0;
}
st.pop();
}
}
int main()
{
int n,m,ans=0;
scanf("%d%d%d",&n,&m,&s);
int x,y;
for(int i=1;i<=m;i++) {scanf("%d%d",&x,&y); add(x,y);}
//tarjan缩点
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
//统计入度
for(int i=1;i<=n;i++)
for(int j=fst[i];j;j=nxt[j])
if(c[v[j]]!=c[i]) in[c[v[j]]]=1;
in[c[s]]=1;//不可以计算包含根节点的强连通分量
//统计答案
for(int i=1;i<=sum;i++) ans+=(in[i]^1);
printf("%d",ans);
return 0;
}