區間重疊的問題:給定包含起始時間s和終止時間t(s < t) 的n個區間段,依據區間重疊情況衍生出來的一系列問題,一般以會議室的安排為外殼作為題目,給定n個會議的開始和結束時間,求相關問題,輸入格式為:
n s1 t1 s2 t2 ... sn tn
以下整理了三種常見題目:
1、最少會議室(最多重疊區間數)
求滿足所有會議安排的最少會議室數量。即最多的相互重疊的區間數量。
如上圖分析可知,可將所有時間點排序,初始化ans=0,遇到起始點+1,遇到終止點-1,即可得到任意區間段的區間重疊數量。
特殊情況:當同一區間點同時為起始點和終止點時(圖中+0點),需將終止點標記排在起始點之前,即先-1再+1,否則會出現錯誤。
時間復雜度:時間主要耗費在排序2n個元素上,復雜度為O(nlogn)。
基於C++的示例代碼如下:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 bool cmp(const pair<int, int> x, const pair<int, int> y){ 6 // 對於相同的區間點,使終點始終在起點之前 7 if(x.first == y.first) return x.second > y.second; 8 return x.first < y.first; 9 } 10 11 int main(){ 12 int n, s, t; 13 vector<pair<int, int> > vals; 14 cin >> n; 15 16 for(int i = 0; i < n; i++){ 17 cin >> s >> t; 18 vals.push_back(pair<int, int>(s, 0)); 19 vals.push_back(pair<int, int>(t, 1)); 20 } 21 sort(vals.begin(), vals.end(), cmp); 22 23 int K = 0, ans = 0; 24 for(int i = 0; i < vals.size(); i++){ 25 // 遇到起點+1 26 if(vals[i].second == 0){ 27 K++; 28 ans = ans > K ? ans : K; 29 } 30 // 遇到終點-1 31 else K--; 32 } 33 cout << ans << endl; 34 return 0; 35 }
2、最多數量會議安排(最多無重疊的區間數量)
在僅有一個會議室的情況下,求最多能滿足的會議數量。即最多的無相互重疊的區間數量。
如上圖所示,可用貪心法解決,按照會議結束時間排序,首先取第一個結束的會議,並記錄結束時間end_t(圖中紅色點),依次遍歷后續會議,若某會議的開始時間不小於end_t(圖中藍色點),則可安排該會議,同時更新end_t。
特殊情況:當結束時間相等時,開始時間的順序其實無關緊要,如上圖第三四行,兩個會議均可,且安排后end_t相同,對后續安排不影響;若同時要求優先安排較長時間的會議、或者保證會議室總使用時間較長,可以在結束時間相等的情況下,使開始時間升序排列。
時間復雜度:時間主要耗費在排序n個元素上,復雜度為O(nlogn)。
基於C++的示例代碼如下:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 bool cmp(const pair<int, int> x, const pair<int, int> y){ 6 // 對於結束時間相同的,按起始時間升序排列 7 if(x.second == y.second) return x.first < y.first; 8 // 按結束時間升序排列 9 return x.second < y.second; 10 } 11 12 int main(){ 13 int n, s, t; 14 vector<pair<int, int> > vals; 15 cin >> n; 16 17 for(int i = 0; i < n; i++){ 18 cin >> s >> t; 19 vals.push_back(pair<int, int>(s, t)); 20 } 21 sort(vals.begin(), vals.end(), cmp); 22 23 int end_t = -1, ans = 0; 24 for(int i = 0; i < vals.size(); i++){ 25 // 若當前會議開始時間不小於上一個安排會議的結束時間,則可安排 26 if(vals[i].first >= end_t){ 27 ans++; 28 end_t = vals[i].second; 29 } 30 } 31 cout << ans << endl; 32 return 0; 33 }
3、最長時間會議安排(最多無重疊的區間長度)
在僅有一個會議室的情況下,求最長的能滿足的會議時間。即最多無相互重疊的區間長度。
該問題用動態規划解決,首先將會議按結束時間排序,dp[i]表示以安排第i個會議作為最后一個會議時前i個會議能滿足的最長時間,遞推關系為dp[i] = (ti - si) + MAX{dp[j]},其中0<=j<i且si >= tj。
特殊情況:對於結束時間相等的會議,按照開始時間順序排序。
時間復雜度:排序n個元素復雜度為O(nlogn),動態規划復雜度為O(n2),整體復雜度為O(n2)。
基於C++的示例代碼如下:
1 #include <iostream> 2 #include <algorithm> 3 #include <vector> 4 using namespace std; 5 6 bool cmp(const pair<int, int> x, const pair<int, int> y){ 7 // 對於結束時間相同的,按起始時間升序排列 8 if(x.second == y.second) return x.first < y.first; 9 // 按結束時間升序排列 10 return x.second < y.second; 11 } 12 13 int main(){ 14 int n, s, t; 15 vector<pair<int, int> > vals; 16 cin >> n; 17 18 for(int i = 0; i < n; i++){ 19 cin >> s >> t; 20 vals.push_back(pair<int, int>(s, t)); 21 } 22 sort(vals.begin(), vals.end(), cmp); 23 24 vector<int> dp(n, 0); 25 int ans = 0; 26 for(int i = 0; i < vals.size(); i++){ 27 int mmax = 0; 28 for(int j = 0; j < i; j++){ 29 // mmax = max{dp[j]}, for all 0 <= j < i and si >= tj 30 if((vals[i].first >= vals[j].second) && (dp[j] > mmax)){ 31 mmax = dp[j]; 32 } 33 } 34 // dp[i] = (ti - si) + max{dp[j]} 35 dp[i] = vals[i].second - vals[i].first + mmax; 36 ans = ans > dp[i] ? ans : dp[i]; 37 } 38 cout << ans << endl; 39 return 0; 40 }