[HAOI2016]食物链

原题链接: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;
}

 

posted @ 2018-01-21 08:18  Excim  阅读(134)  评论(0编辑  收藏  举报