拓撲排序
拓撲排序(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;
}
一直將自己的學習經驗分享給有需要的人。
我是小鄭,一個堅持不懈的小白