線上視訊教育網站SSM,spring boot(小型教育網站的開發與建設)
阿新 • • 發佈:2021-08-06
一、試題講解
https://www.cnblogs.com/CJYBlog/p/12198894.html
二、拓撲排序完整程式碼
#include <bits/stdc++.h> using namespace std; const int N = 5005; //生物種類上限 const int M = 500005; //吃與被吃的關係數上限 const int MOD = 80112002; //最大食物鏈數量模 int n; //生物種類 int m; //吃與被吃的關係數 int ans; //為最大食物鏈數量模上 80112002 的結果 vector<int> edge[N]; //儲存DAG圖的鄰接表 queue<int> q; //廣搜的佇列 int f[N]; //每個生物種類的食物鏈最長值 int ind[N]; //每個生物種類的入度 int out[N]; //每個生物種類的出度 /** 總結: 1、誰向誰有一條有向邊是需要強調的,x->y與 y->x是完全不同的。本題是說x被y吃掉,記錄的是這個關係, 即x->y有一條有向邊。 2、需要進行模的題,需要每一步操作結果時,都進行一次MOD操作,防止中間過程資料過大。 3、獲得的所有食物鏈數量加在一起,再MOD,才是結果。 4、DAG+廣度優先搜尋= "拓撲排序" !!! !!!!目的:使得在搜到點x時,所有能達到點x的點,已經被搜過了。 5、拓撲排序思路:把入度為0的入到佇列,然後找到它的所有出邊,對接點入度-1,如果對接點入度為0,則再入佇列。 6、每一個以當前結點為終止結點的路徑條數,等於上一級的N個結點,每個結點條數的和。 7、在DAG的廣度搜索中+動態規劃是本題的難點,注意base case的理解。 8、入度為0的,是第一批入佇列的,它們是食物鏈的底層(草根)。出度為0的是食物鏈的頂層,是老虎,鷹,鯊魚等。 9、出度是否為0,是判斷是不是再繼續入佇列的條件。 10、入度為0的所有結點,它們的食物鏈條數和就是答案 11、與深度優先不同,拓撲排序,需要同時維護出度和入度,出度在錄入資料後,維護不變;入度隨演算法的深入, 一直在-1,直到為0. */ int main() { cin >> n >> m; //m種關係 for (int i = 1; i <= m; i++) { int x, y; cin >> x >> y; //x被y吃掉 out[x]++; //點x的出度+1 ind[y]++; //點y的入度+1 edge[x].push_back(y); //用鄰接表記錄下食物鏈的關係,x被y吃掉,由x向y引一條有向邊 } //找到所有入度為0的點,放入廣度優先搜尋的佇列 for (int i = 1; i <= n; i++) if (!ind[i]) q.push(i), f[i] = 1; //f[i]=1:base case,它到它的每個孩子都有一條出邊,就是一條路徑 //廣度優先搜尋DAG,就是拓撲排序的模板 while (!q.empty()) { int x = q.front(); q.pop(); for (int i = 0; i < edge[x].size(); i++) { //遍歷所有出邊 int y = edge[x][i]; //目標結點 f[y] = (f[x] + f[y]) % MOD; //在計算f[y]之前, f[x]都是計算過的了。 //對接點入度-1,抹去這條入邊 ind[y]--; //如果入度為0,則入佇列,準備處理它 if (!ind[y]) q.push(y); } } //遍歷所有結點,如果出度為0,描述 for (int i = 1; i <= n; i++) if (!out[i]) ans = (ans + f[i]) % MOD; cout << ans << endl; return 0; }