洛谷題集——最大食物鏈計數(動態規劃、圖的基本應用、BFS)

題目

給你一個食物網,你要求出這個食物網中最大食物鏈的數量。
(這裏的“最大食物鏈”,指的是生物學意義上的食物鏈,即最左端是不會捕食其他生物的生產者,最右端是不會被其他生物捕食的消費者。)
由於這個結果可能過大,你只需要輸出總數模上 80112002的結果。

輸入格式
第一行,兩個正整數n、m,表示生物種類 n 和喫與被喫的關係數 m。

接下來 m 行,每行兩個正整數,表示被喫的生物A和喫A的生物B。

輸出格式
一行一個整數,爲最大食物鏈數量模上 80112002的結果。

輸入輸出樣例
輸入
5 7
1 2
1 3
2 3
3 5
2 5
4 5
3 4
輸出
5
說明/提示
各測試點滿足以下約定:
測試數據說明


樣例中食物鏈關係圖
食物鏈
動態規劃——物種關係

  • 最大食物鏈計數 = 以 1 爲起點的食物鏈數量

  • ①、以 1 爲起點的食物鏈數量 = 以 2 爲起點的食物鏈數量 + 以 3 爲起點的食物鏈數量
    最大食物鏈計數 = 以 2 爲起點的食物鏈數量 + 以 3 爲起點的食物鏈數量

  • ①、以 2 爲起點的食物鏈數量 = 以 3 爲起點的食物鏈數量 + 以 5 爲起點的食物鏈數量
    ②、以 3 爲起點的食物鏈數量 = 以 5 爲起點的食物鏈數量 + 以 4 爲起點的食物鏈數量
    最大食物鏈計數 = 3 * 以 5 爲起點的食物鏈數量 + 以 3 爲起點的食物鏈數量 + 2 * 以 4 爲起點的食物鏈數量

  • ①、以 4 爲起點的食物鏈數量 = 以 5 爲起點的食物鏈數量
    ②、以 5 爲起點的食物鏈數量 = 1
    最大食物鏈計數 = 5 * 以 5 爲起點的食物鏈數量 = 5

上面是正推的過程
爲了方便理解,代碼中通過逆推的方式實現
①、記錄每個物種能喫多少物種。(eat)
②、記錄每個物種能被多少種物種喫。(beat)
③、記錄每個物種能食用那些物種。(vector)

//逆推
#include<bits/stdc++.h>
using namespace std;
int eat[5010], beat[5010];
vector <int> gx[5010];
int total[5010], ans=0;
int main(){
	memset(eat, 0, sizeof(eat));
	memset(beat, 0, sizeof(beat));
	memset(total, 0, sizeof(total));
	int n, m;
	cin>>n>>m;
	for(int i=0; i<m; i++){
		int a, b;
		cin>>a>>b;
		beat[a]++;		// 可喫 a 物種的數量
		eat[b]++;		// b 物種可喫的數量
		gx[b].push_back(a);	// b 可喫 a 
	}
	
	queue <int> q;
	//初始化
	for(int i=1; i<=n; i++){
		if(beat[i]==0){
			total[i]=1;		//每個“終點”賦值爲1
			q.push(i);		//並插入隊列中
		}
	}
	
	while(!q.empty()){
		int top = q.front();
		q.pop();
		for(int i=0; i<gx[top].size(); i++){
			int k = gx[top][i];
			//推出以 k 爲起點的食物鏈數
			total[k] = (total[k]+total[top])%80112002;
			//減去物種 k 可被其他物種喫的數量
			beat[k]--;
			//當beat[k]==0
			//total[k]爲以 k 爲起點的最大食物鏈數 
			if(beat[k]==0){
				//回到起點
				if(eat[k]==0){
					ans = (ans + total[k])%80112002;
				}
				//未到起點
				else{
					q.push(k);
				}
			}
		}
	}
	cout<<ans;
	return 0;
}

如果文章對你有幫助,請給個贊吧~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章