題意#
題目給定 \( n \) 個任務,每個任務有「耗費的時間」與「死線(Deadline)」。
一次只能處理一個任務,執行順序可自行安排。
每完成一個任務的獎金為「該任務的死線 - 實際完成的時間點」(若超過死線則為負數倒扣)。
我們需要求出在最佳排程下,能獲得的最高總獎金。
思路#
將總獎金公式拆解:
總獎金 = (死線總和) - (實際完成時間總和)。
由於「死線總和」為固定常數,無論任務順序如何都不會改變。
因此目標轉化為:讓「實際完成時間總和」最小化。
要最小化整體完成時間,可採用作業系統中經典的「短作業優先(Shortest Job First)」排程策略。
優先處理耗時最短的任務,能讓後續任務提早開始,進而壓低所有任務累積的完成時間。
在實作上,忽略死線的順序,將任務依「耗費時間」從小到大排序。
依序執行並累加目前的經過時間,同時計算每項任務的獎金,加總後即為最高總獎金。
程式碼#
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
#define INF LONG_LONG_MAX/1000
#define WA() cin.tie(0)->sync_with_stdio(0)
#define all(x) (x).begin(), (x).end()
#define int long long
#define PII pair<int, int>
signed main() { WA();
int n; cin >> n;
// 儲存每個任務的 {耗費時間, 死線}
vector<PII> v(n);
for (auto &i : v) cin >> i.fi >> i.se;
// 按照「耗費時間 (fi)」從小到大進行排序,實踐 Shortest Job First 貪心策略
sort(all(v));
// now 記錄現實經過的時間,ans 記錄累積拿到的獎金
int now, ans; now = ans = 0;
// 按照排好的順序依序執行任務
for (auto &[dur, dl] : v) {
// 完成此任務後,時間往後推進
now += dur;
// 結算這份任務的獎金(死線減去實際完成時間)並累加
ans += dl-now;
}
// 輸出最多能拿到的總獎金
cout << ans;
}
