题目链接:专题训练3-图论 - Virtual Judge (vjudge.net)
题目:现在给你 nn 个物种和 mm 条能量流动关系,求其中的食物链条数。
物种的名称为从 11 到 nn 的编号。
mm 条能量流动关系形如
a_1a1 b_1b1
a_2a2 b_2b2
a_3a3 b_3b3
… …
a_mam b_mbm
其中 a_i \ b_iai bi 表示能量从物种 a_iai 流向物种 b_ibi。注意单独的一种孤立生物不算一条食物链。
输入格式
第一行两个整数 nn 和 mm,接下来 mm 行每行两个整数 a_i \ b_iai bi 描述 mm 条能量流动关系。
(保证输入数据符合生物学特点,且不会有重复的能量流动关系出现)
[tips:应该是指没有环,也没有重边]
输出格式
一个整数,即食物网中的食物链条数。
思路:拓扑排序,开两个数组分别记录出度和入度,和平常的拓扑排序不同的是这题要求算食物链的总数,将每个位于食物链低端的dp赋值为1(即入度为0的点),然后每次dp[捕食者]+=dp[被捕食者],当入度和出度都为0时,ans+=dp,最终得到答案。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,res=0;
vector<int>g[100005];
int in[100005],out[100005],dp[100005];
void tuopu()
{
queue<int>que;
for(int i=1;i<=n;i++)
{
if(!in[i]) que.push(i),dp[i]=1;
}
while(que.size()){
int u=que.front();
que.pop();
for(int i=0;i<g[u].size();i++)
{
in[g[u][i]]--;
dp[g[u][i]]+=dp[u];
if(!in[g[u][i]]&&!out[g[u][i]]) res+=dp[g[u][i]];
else if(!in[g[u][i]]) que.push(g[u][i]);
}
}
}
int main()
{
for(int i=1;i<=n;i++)
{
g[i].clear();
}
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
g[a].push_back(b);
in[b]++;
out[a]++;
}
tuopu();
printf("%d",res);
}