八段第二课tarjan算法总结
D 构造可达性
解法
首先我们缩点,因为里面都是可达的。
然后我们可以发现,缩完点之后,如果一个点入度为 $0$,那么就说明没有点能到这个点,我们就得答案++。
最后,注意判断 $s$ 所在的点是否有被算入答案。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include <bits/stdc++.h> using namespace std;
const int N = 2000010; int h[N],e[N],ne[N],idx;
int n,m,s; int times=1; int color[N]; int dfn[N],low[N]; bool vis[N]; int cc=0; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int stk[N]; int top=0; void dfs(int u) { vis[u]=1; dfn[u]=times,low[u]=times++; stk[++top]=u; for(int i=h[u];i!=-1;i=ne[i]) { if(!dfn[e[i]]) { dfs(e[i]); low[u]=min(low[u],low[e[i]]); } else if(vis[e[i]])low[u]=min(low[u],dfn[e[i]]); } if(low[u]==dfn[u]) { int x=-1; cc++; while(x!=u) { x=stk[top]; top--; vis[x]=0; color[x]=cc; } } } int x[5010],y[5010]; int rd[5010];
int main() { scanf("%d%d%d",&n,&m,&s); memset(h,-1,sizeof h); for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); x[i]=a,y[i]=b; } for(int i=1;i<=n;i++) { if(!dfn[i]) dfs(i); } for(int i=1;i<=m;i++) { int a=color[x[i]],b=color[y[i]]; if(a!=b) rd[b]++; } int ans=0; for(int i=1;i<=cc;i++) if(!rd[i]) ans++; if(!rd[color[s]]) ans--; cout<<ans; }
|