一:本题意:给定一张包含 n 个生物、m 条捕食关系的食物网,可形式化为一张有向无环图(DAG)。每条有向边由一对整数 v,u 表示:生物 u 捕食生物 v。
(1)起点是生产者:不会捕食其它生物,即在图中出度为 0 的节点
(2)终点是顶级消费者:不会被其它生物捕食,即在图中入度为 0 的节点
问题:求请计算图中这样的食物链共有多少条 二:分析思虑:
1:从题意可知,该食物链构成了一个天然的图结构,因此需要考虑使用邻接表。
2:问题提到计算途中的食物链有多少条,那就直接求顶级猎食者到各底层猎物的总路径,考虑使用后续递归遍历。在后续递归遍历中,父节点的食物链是所有子节点的食物链的和,因此考虑使用动态规划。
3:由于求所有顶级猎食者的食物链,所有需要获得所有顶级猎食者,最后的答案是所有顶级猎食者的食物链之和。
三:解法: 1:定义图的存储结构adj,每个adj[u]表示猎食者的所有猎物。
2:定义dp,dp[i]表示猎食者i的食物链数量,起始时赋初值为-1,表示该猎食者食物链数量还未获得。
3:hasPredator判断i是否有猎物,如果为false,则表明是顶级猎食者,hasPrey判断是否有猎物,如果为false,表明是生产者。
4:定义dfs算法,计算每个猎食者的食物链数量,dp[u]:
(1)边界条件:如果dp[u]!=-1,返回;如果是生产者则令dp[u]=1,然后返回;
(2)递推过程:猎食者u的食物链是所有猎物的食物连之和。
5:具体过程:
(1)对每个顶级猎食者调用dfs算法,并求和,此结果既为所有猎食者的食物链,但是需要排除一种情况。
(2)由于在深度递归中将所有既是顶级猎食者又是生产者的节点dp[u]初值设置为1,但是该情况与题意不符,所以减去。
#include <iostream>
#include <vector>
using namespace std;
//定义存储结构
vector<vector<int>> adj;
//定义dp
vector<int> dp;
//定义判断顶级猎食者标记
vector<bool> hasPredator;
//定义判断是否是消费者
vector<bool> hasPrey;
void dfs(int u){
if(dp[u] != -1){
return;
}
if(adj[u].empty()){
dp[u]=1;
return;
}
dp[u]=0;
for(int v:adj[u]){
dfs(v);
dp[u]+=dp[v];
}
}
int main() {
int n,m;
cin>>n>>m;
adj.resize(n+1);
dp.resize(n+1,-1);
hasPredator.resize(n+1,false);
hasPrey.resize(n+1,false);
for(int i=1;i<=m;i++){
int u,v;
cin>>v>>u;
adj[u].push_back(v);
hasPredator[v]=true;
hasPrey[u]=true;
}
vector<int> topPredators;
for(int i=1;i<=n;i++){
if(hasPredator[i]==false){
topPredators.push_back(i);
}
}
int ans=0;
for(int u:topPredators){
dfs(u);
ans+=dp[u];
}
for (int i = 1; i <= n; i++) {
if (!hasPredator[i] && !hasPrey[i]) {
// 既是顶级消费者(没有捕食者)又是生产者(没有食物)
ans--; // 减去1
}
}
cout<<ans<<endl;
return 0;
}



京公网安备 11010502036488号