# 0-22 priority_queue 講義不是我寫的,網址在此 https://emanlaicepsa.github.io/2020/10/21/0-index/ 我只是將自己寫的練習題程式碼記錄下來。 最後更新日期:2024年10月9日 ## [TIOJ: 1161. 4.虛擬番茄online](https://tioj.ck.tp.edu.tw/problems/1161) 本題在〈[0-20 set](https://hackmd.io/@yizhewang/ryxv_Axyyl)〉有出現過,當時是用 Python 的 bisect 函式庫及 C++ 的 set 解題,因為是要儲存資料中的3個最小值,也可以使用 priority queue 解題。 ### Python 程式碼 無法通過測試,第4筆測資超過記憶體上限。 ```python= import heapq as hq T = int(input()) # 測試資料組數 for _ in range(T): s = [] # 儲存目前需要的能力值,用 heapq,預設由小到大排序,資料要加上負號 n, k = map(int, input().split()) # 可以學的技能總數 n,要學的技能總數 k sa = [] # 學習各技能需要的能力值 s、a for _ in range(n): sa.append(list(map(int, input().split()))) # 讀取資料給 sa sa.sort() # 由小到大排序 ans = 1000000001 # 答案先預設為很大的值 for i in range(n): # 依序讀取 sa 的資料 hq.heappush(s, -sa[i][1]) # 於 s 插入 -sa[i][1] 並保持順序 if len(s) > k: hq.heappop(s) # 如果 s 的數量大於 k,移除量值最大的資料 if len(s) == k: # 如果 s 的數量等於 k,更新 ans 為 ans 及 sa[i][0] - s[0] 較小值 ans = min(ans, sa[i][0] - s[0]) print(ans) ``` ### C++ 程式碼 執行時間最久約為 370 ms,使用記憶體最多約為 13052 kB,通過測試。執行速度比 multiset 快很多。 ```cpp= #include <iostream> #include <queue> #include <utility> #include <algorithm> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); int T; cin >> T; // 測試資料組數 for(int i=0; i<T; i++) { priority_queue<int> s; // 儲存目前需要的能力值,由大到小排序 int n, k; cin >> n >> k; // 可以學的技能總數 n,要學的技能總數 k pair<int, int> sa[n]; // 學習各技能需要的能力值 s、a for(int i=0; i<n; i++) cin >> sa[i].first >> sa[i].second; // 讀取資料給 sa sort(sa, sa+n); // 由小到大排序 int ans = 1000000001; // 答案先預設為很大的值 for(int i=0; i<n; i++) { // 依序讀取 sa 的資料 s.push(sa[i].second); // 於 s 插入 sa[i].second 並保持順序 if (s.size() > (size_t)k) s.pop(); // 如果 s 的數量大於 k,移除第一項 if (s.size() == (size_t)k) // 如果 s 的數量等於 k,更新 ans 為 ans 及 sa[i].first + s.top() 較小值 ans = min(ans, sa[i].first + s.top()); } cout << ans << "\n"; } return 0; } ``` ## [TIOJ: 1231 . 寵物雞問題](https://tioj.ck.tp.edu.tw/problems/1231) ### Python 程式碼 第5筆測資會遇到 Runtime Error。 ```python= import heapq as hq n = int(input()) # 食物數量 n food = [] # 食物的 (保存期限, 熱量) for _ in range(n): # 讀取 n 行資料 h, d = map(int, input().split()) # 熱量 h,保存期限 d food.append((d, h)) # 將 (d, h) 加入 food food.sort(reverse=True) # 由大到小排序 k = int(input()) # 結束時間 k ans = 0 # 答案 idx = 0 # 由 food 讀取資料用的索引值 t = k # 時刻 t 預設為 k pq = [] # 儲存目前未過期的食物熱量,為了將量值由大到小排序,要加負號 while t > 0: # t > 0 繼續執行 while idx < n and food[idx][0] >= t: # 如果 idx 還沒有出界而且 food[idx] 還沒有過期 hq.heappush(pq, -food[idx][1]) # 將 -food[idx][1] 加入 pq idx += 1 # idx 加 1 if not pq: # 如果 pq 沒有資料 ans -= t - food[idx][0] # ans 減去 (t - 下一個時物過期的時間) t = food[idx][0] # t 重設為下一個時物過期的時間 else: # 如果 pq 有資料 ans += -hq.heappop(pq) # 移除 pq 最上方一項,變為正值再加到 ans t -= 1 # 時間減 1 print(ans) ``` ### C++ 程式碼 執行時間共約為 72 ms,使用記憶體最多約為 4556 kB,通過測試。food 要宣告在 main 外面,如果放在 main 內的第12行,第5筆測資會超時。 ```cpp= #include <iostream> #include <utility> #include <algorithm> #include <queue> using namespace std; pair<int, int> food[100005]; // 食物的 (保存期限, 熱量) int main() { ios::sync_with_stdio(0); cin.tie(0); int n; cin >> n; // 食物數量 n //pair<int, int> food[n]; // 食物的 (保存期限, 熱量) for(int i=0; i<n; i++) cin >> food[i].second >> food[i].first; // 讀取 n 行資料 sort(food, food+n, greater<pair<int, int>>()); // 由大到小排序 int k; cin >> k; // 結束時間 k int ans = 0, idx = 0, t = k; // 答案 ans,由 food 讀取資料用的索引值 idx,時刻 t priority_queue<int> pq; // 儲存目前未過期的食物熱量,由大到小排序 while(t > 0) { // t > 0 繼續執行 while(idx < n && food[idx].first >= t) { // 如果 idx 還沒有出界而且 food[idx] 還沒有過期 pq.push(food[idx].second); // 將 food[idx].second 加入 pq idx++; // idx 加 1 } if(pq.empty()) { // 如果 pq 沒有資料 ans -= t - food[idx].first; // ans 減去 (t - 下一個時物過期的時間) t = food[idx].first; // t 重設為下一個時物過期的時間 } else { // 如果 pq 有資料 ans += pq.top(); pq.pop(); // ans 加上 pq 最上方一項,再移除此項 t--; // 時間減 1 } } cout << ans << "\n"; return 0; } ``` ------ ###### tags:`演算法`、`APCS`、`Python`、`C++`