CSS學習--值與單位
阿新 • • 發佈:2022-03-31
關鍵路徑 p3 清華複試上機題
題目描述
小H為了完成一篇論文,一共要完成n個實驗。其中第i個實驗需要a[i]的時問去完成。小H可以同時進行若干實驗,但存在一些實驗,只有當它的若干前置實驗完成時,才能開始進行該實驗。同時我們認為小H在一個實驗的前置實驗都完成時,就能馬上開始該實驗。
為了讓小H 儘快完成論文,需要知道在最優的情況下,最後一個完成的實驗什麼時候完成。
小H還想知道,在保證最後一個實驗儘快完成的情況下(即保證上一間的答案不變),他想知道每個實驗最晚可以什麼時候開始。
設第i個實驗最早可能的開始時問為fi,不能響最後一個實驗完成時間的最晚開始時間為gi,請證明\(\prod_{i=0}^{n}(g_i-f_i+1)\)除以\(10^9+7\)所得的餘數能夠保證題目有解。
輸入
從標淮輸入讀入資料。
第一行輸入兩個整數n,m。
第二行輸入n個正整數 a,a[2],…,a[n],描述完成每個實驗所需要的時間。
接下來讀入 m 行,每行讀入兩個整數u,v,表示編號為u的實驗是編號為v的實驗的前置實驗。
對於所有的輸入資料,都滿足\(1\leqslant n \leqslant 10^5\),\(1\leqslant m \leqslant 5×10^5\),\(1\leqslant a_i\leqslant 10^6\).
輸出
輸出到標準輸出。
第一行輸出一個整數,表示完成實驗的時間。
第二行輸出一個整數表示\(\prod_{i=0}^{n}(g_i-f_i+1)\)除以\(10^9+7\)所得的餘數。
樣例輸入
7 5
11 20 17 10 11 17 17
5 4
6 1
7 3
2 4
2 1
樣例輸出
34
7840
解題思路
求關鍵路徑的長度,記錄每個實驗最早開始時間和最晚開始時間。典型關鍵路徑問題。
程式碼實現
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 7; const int INF = INT_MAX; const int MOD = 1e9 + 7; vector<int> graph[maxn]; int inDegree[maxn]; ll earliest[maxn]; ll latest[maxn]; ll timee[maxn]; ll criticalPath(int n) { vector<int> topology; queue<int> q; for (int i = 1; i <= n; ++i) { if (inDegree[i] == 0) { q.push(i); } } ll totalTime = 0;//總耗時 while (!q.empty()) { int u = q.front(); topology.push_back(u); q.pop(); for (int i = 0; i < graph[u].size(); ++i) { int v = graph[u][i]; inDegree[v]--; earliest[v] = max(earliest[v], timee[u] + latest[u]);//取最大值的原因:只有當前結點的所有前驅結點活動全部完成,才能完成本結點 if (inDegree[v] == 0) { q.push(v); totalTime = max(totalTime, earliest[v] + timee[v]);//關鍵路徑長度為最大路徑長度的路徑 } } } for (int i = topology.size() - 1; i >= 0; --i) {//逆拓撲排序求最遲開始時間 int u = topology[i]; if (graph[u].size() == 0) { latest[u] = totalTime - timee[u];//出度為0的點,最晚開始時間為關鍵路徑長度減去其耗費時間 } else { latest[u] = INF;//後面要求最小值,初始化為極大值 } for (int j = 0; j < graph[u].size(); ++j) { int v = graph[u][j]; latest[u] = min(latest[u], latest[v] - timee[u]);//非出度為0的點,最晚開始時間為所有其後續節點最晚開始時間減去該節點耗費時間的最小值 } } return totalTime; } int main() { int n, m; while (cin >> n >> m) { memset(graph, 0, sizeof graph); memset(inDegree, 0, sizeof inDegree); memset(earliest, 0, sizeof earliest); memset(latest, 0, sizeof latest); memset(timee, 0, sizeof timee); for (int i = 1; i <= n; i++) { cin >> timee[i]; } while (m--) { int from, to; cin >> from >> to; graph[from].push_back(to); inDegree[to]++; } ll totalTime = criticalPath(n); ll answer = 1; for (int i = 1; i <= n; ++i) { answer *= latest[i] - earliest[i] + 1; answer %= MOD; } cout << totalTime << endl << answer << endl; } return 0; }