算法——關於區間重疊的幾個問題


 

區間重疊的問題:給定包含起始時間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 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM