题目描述
输入格式
第一行两个整数 n 和 m,接下来 m 行每行两个整数 ai,bi 描述 m 条能量流动关系。
(保证输入数据符合生物学特点,且不会有重复的能量流动关系出现)
[tips:应该是指没有环,也没有重边]
输出格式
一个整数,即食物网中的食物链条数。
输入样例
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
数据范围
1≤N≤100000,0≤m≤200000
保证答案不会超过
int
的最大值
参考思路
根据食物链描述,我们首先找到入度为0的点作为开头,找到出度为0的点作为结尾,那么从开头走到结尾就成为了一条食物链。
我们可以用一个dp数组记录有多少种方法走到这个点,那么这样到最后只要找出全部出度为0的点路径,加起来即可。
因为数据范围,我们用邻接表存储。
参考代码
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define F 200000+5
using namespace std;
int n, m, r[F], c[F], dp[F], tot, nxt[F], head[F];
bool vis[F];
int ans = 0;
struct ed //邻接表存储
{
int from, to;
}e[2*F];
void build(int f, int t)
{
++tot;//记录边数
e[tot].from = f;
e[tot].to = t;
nxt[tot] = head[f];//记录上一次的i的边
head[f] = tot;//这表示点i最新的边
}
void dfs(int x)
{
for (int i = head[x]; i; i = nxt[i])//最新边,然后到最旧边 邻接表遍历
{
int f = e[i].from;
int t = e[i].to;
dp[t] += dp[f];//表示有多少种办法走到这个点
r[t]--;
if (r[t] == 0)
dfs(t);
}
}
int main()
{
int en;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
dp[i] = 0;
for (int i = 1; i <= m; i++)
{
int x, y;
cin >> x >> y;
r[y]++;//每个点的出度和入度
c[x]++;
build(x, y);
}
for (int i = 1; i <= n; i++)
if (r[i] == 0 && c[i] != 0)//不包括孤立的点 找开头
{
dp[i] = 1, vis[i] = 1;
}
for (int i = 1; i <= n; i++)
if (vis[i])//从入度为0的点开始搜
{
dfs(i);
}
for (int i = 1; i <= n; i++)
if (c[i] == 0)//遍历出度为0的点
ans += dp[i];
printf("%d", ans);
return 0;
}
感谢您的阅读!(*^▽^*)