洛谷P3183 [HAOI2016]食物链
题目描述
如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数。
物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a3 b3......am-1 bm-1am bm其中ai bi表示能量从物种ai流向
物种bi,注意单独的一种孤立生物不算一条食物链。
输入格式
第一行两个整数n和m,接下来m行每行两个整数ai bi描述m条能量流动关系。(数据保证输入数据符号生物学特点,且不会
有重复的能量流动关系出现)1<=N<=100000 0<=m<=200000题目保证答案不会爆 int
输出格式
一个整数即食物网中的食物链条数
题解:DAG上dp的入门题目,大部分题解都是记忆化搜索版的即一条一条食物链的找,找到某个出度为零的点时,就找到了一条极大
食物链,我写的是qbxt zhhx大佬写的数组递推版,用一个队列维护一下,因为是DAG,所以每个点的食物链条数都是它所有前置节点
的食物链条数之后,没处理一次,入度减一,当入度为零时,代表已经转移完成,最后统计所有出度为零即食物链最后一个点的答案即可。
转台转移方程:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #define maxn 100005 7 8 using namespace std; 9 10 struct node 11 { 12 int ed,nxt; 13 }; 14 node edge[200005]; 15 int ind[maxn],first[maxn],dp[maxn],n,m,cnt; 16 int out[maxn]; 17 18 inline void add_edge(int s,int e) 19 { 20 cnt++; 21 edge[cnt].ed=e; 22 edge[cnt].nxt=first[s]; 23 first[s]=cnt; 24 return; 25 } 26 27 queue <int> q; 28 29 int main() 30 { 31 scanf("%d%d",&n,&m); 32 for(int i=1;i<=m;i++) 33 { 34 int s,e; 35 scanf("%d%d",&s,&e); 36 add_edge(s,e); 37 ind[e]++; 38 out[s]++; 39 } 40 for(int i=1;i<=n;i++) 41 if(ind[i]==0) 42 { 43 if(out[i]) dp[i]=1; 44 q.push(i); 45 } 46 while(!q.empty()) 47 { 48 int p=q.front(); q.pop(); 49 for(int i=first[p];i;i=edge[i].nxt) 50 { 51 int e=edge[i].ed; 52 dp[e]+=dp[p]; ind[e]--; 53 if(ind[e]==0) q.push(e); 54 } 55 } 56 int ans=0; 57 for(int i=1;i<=n;i++) 58 if(out[i]==0) ans+=dp[i]; 59 printf("%d",ans); 60 return 0; 61 }