【bzoj 4562】食物链(DP+拓扑)HAOI2016

http://www.lydsy.com/JudgeOnline/problem.php?id=4562

题目描述

如图所示为某生态系统的食物网示意图,据图回答第1小题【满满的都是生物的气息emmmmm】
现在给你n个物种和m条能量流动关系,求其中的食物链条数。
物种的名称为从1到n编号
M条能量流动关系形如
a1 b1
a2 b2
a3 b3
……
am-1 bm-1
am bm
其中ai bi表示能量从物种ai流向物种bi,注意单独的一种孤立生物不算一条食物链

输入

第一行两个整数n和m,接下来m行每行两个整数ai bi描述m条能量流动关系。
(数据保证输入数据符号生物学特点,且不会有重复的能量流动关系出现)
1<=N<=100000 0<=m<=200000
题目保证答案不会爆 int

输出

一个整数即食物网中的食物链条数

样例输入

10 16
1 2
1 4
1 10
2 3
2 5
4 3
4 5
4 8
6 5
7 6
7 9
8 5
9 8
10 6
10 7
10 9

样例输出

9

一句话的切题


在一个给定的DAG图中,求任意一条从入度为0的点到出度为0的点的方案数,其中不包括入度和出度都为0的点

思路:

一上来就看成了和上一道并查集的食物链一样的题,恍惚了一下才发现这是个什么东西。餐后小甜点的训练中A题拓扑的题目就是这一道,用裸的迷迷的拓扑排序竟然还过了三个点(姿势好姿势好哈哈哈尬)
事实上没看出来应该用拓扑套上什么,各种跪着哭,最后听他们说是要dp,但是超级没有觉得DP在哪里。。。
首先入度和出度都为0的点要特判,然后设f[i]表示从某个入度为0的点到点i的方案数,然后按照类似拓扑排序的方法,由入度为0的点更新其它点,在此过程中进行累加。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define ri register int
typedef long long LL;
using namespace std;
const int sz = 100010;
inline void read(int &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    if(f) x*=-1;
}
inline void we(int x){
    if(x<0) putchar('-'),x*=-1;
    if(x/10) we(x/10);
    putchar(x%10+'0');
}
int n,m,to[sz<<1],fir[sz],nxt[sz<<1],tot;
int cd[sz],rd[sz],ans,f[sz];
inline void add(int f,int t){
    to[++tot]=t;
    nxt[tot]=fir[f];
    fir[f]=tot;
}
queue<int>q;
int main()
{
    int x,y;
    read(n),read(m);
    for(ri i=1;i<=m;++i)
    {
        read(x),read(y);
        add(x,y);
        cd[x]++,rd[y]++;
    }
    for(ri i=1;i<=n;++i)
    {
        if(!rd[i])
        {
            if(cd[i]) f[i]=1;
            q.push(i);
        }
    }
    while(!q.empty())
    {
        x = q.front();//这个x的定义问题有可能会造成3组超时...
        q.pop();
        for(ri i=fir[x];i;i=nxt[i])
        {
            f[to[i]]+=f[x],rd[to[i]]--;
            if(!rd[to[i]])
                q.push(to[i]);
        }
    }
    for(ri i=1;i<=n;++i)
        if(!cd[i])
            ans+=f[i];
    we(ans);
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值