洛谷題集——最大食物鏈計數(拓撲排序)

拓撲排序
拓撲排序(topological-sort)是指由某個集合上的一個偏序得到該集合上的一個全序的操作。拓撲排序常用來確定一個依賴關係集中,事物發生的順序
拓撲排序是對有向無環圖的頂點的一種排序,它使得如果存在一條從頂點A到頂點B的路徑,那麼在排序中B出現在A的後面。
百度圖片


最大食物鏈計數
給你一個食物網,你要求出這個食物網中最大食物鏈的數量。

(這裏的“最大食物鏈”,指的是生物學意義上的食物鏈,即最左端是不會捕食其他生物的生產者,最右端是不會被其他生物捕食的消費者。)

由於這個結果可能過大,你只需要輸出總數模上 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
說明/提示
各測試點滿足以下約定:
題意
洛谷題目鏈接


解題思路
①、對於圖論類型有向無環圖的題,可以採用拓撲排序。
②、對每個節點的路徑進行逐個遞推,最終每個有向無環的終點之和便是答案。
ps:在拓撲排序裏,每個點只會入隊一次,每條邊只會通過一次,時間複雜度爲O(N+M)。
洛谷題解

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll total[5010], ans=0;
int start[5010], end[5010];
vector <int> g[5010];	//採用鄰接表

int main(){
	int n, m, a, b;
	cin.tie(0);
	ios::sync_with_stdio(false); 
	memset(total, 0, sizeof(total));
	memset(start, 0, sizeof(start));
	memset(end, 0, sizeof(end));
	
	cin>>n>>m;
	for(int i=1; i<=m; i++){
		cin>>a>>b;
		start[a]++;			//記錄 a 有多少條出路 
		end[b]++;			//記錄有多少條路徑能到達 b 
		g[a].push_back(b);	//a 可到達 b
	}
	
	//插入全部起點 
	queue <int> q;
	for(int i=1; i<=n; i++){
		if(end[i]==0){	//沒有路徑能到達 i,i爲起點
			total[i]=1;
			q.push(i);
		}
	}
	
	while(!q.empty()){
		int tmp=q.front();
		q.pop();
		//掃描tmp能到達的節點
		for(int i=0; i<g[tmp].size(); i++){
			int k=g[tmp][i];
			total[k] = (total[k]+total[tmp])%80112002;
			end[k]--;				//少一條能到達 k 的路徑 
			
			if(end[k]==0){			//沒有路徑能到達 k 
				if(start[k]==0){	// k 沒有出路 
					ans = (ans + total[k])%80112002;
				}
				else{
					q.push(k);
				}
			}
		}
	}
	cout<<ans; 
	
	return 0;
} 

一直將自己的學習經驗分享給有需要的人。
我是小鄭,一個堅持不懈的小白

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