原题链接:https://www.luogu.org/problemnew/show/3183
拓扑排序题
题意简述:给出一个有向图,求由图中所有入度为零的点出发,有多少种路径到达出度为零的点(单点不计入)。
拓扑排序,现将所有入度为零的点加到队列中,同时用一个数组f表示能达到这个点的路径条数,很显然,路径的零的点x,f[x]=1
由各个点出发,将每个点的方案数加到它所能到达的点上,完成拓扑排序后,将所有出度为零的点的f值相加,用一个vis来记录是否有边连向这个点,判断是否需要忽略掉即可。
#include<cstdio> void read(int &y) { y=0;char x=getchar(); while(x<‘0‘||x>‘9‘) x=getchar(); while(x>=‘0‘&&x<=‘9‘) { y=y*10+x-‘0‘; x=getchar(); } } int n,m,cnt,l=1,r; int d[100005],c[100005],head[100005]; int q[100005],f[100005],vis[100005]; long long sum; struct edge { int u,v; }e[200005]; void add(int u,int v) { e[++cnt].u=head[u]; e[cnt].v=v; head[u]=cnt; } void top(int x) { for(int i=head[x];i;i=e[i].u) { int nxt=e[i].v; d[nxt]--; if(d[nxt]==0) q[++r]=nxt; f[nxt]+=f[x]; } } int main() { read(n);read(m); for(int i=1;i<=m;i++) { int x,y; read(x);read(y); c[x]++;d[y]++; vis[x]++;vis[y]++; add(x,y); } for(int i=1;i<=n;i++) { if(d[i]==0) { q[++r]=i; f[i]=1; } } while(l<=r) { top(q[l]); l++; } for(int i=1;i<=n;i++) { if(c[i]==0&&vis[i]!=0) sum+=f[i]; } printf("%lld",sum); return 0; }