題目均來自acwing.com
AcWing 905. 區間選點
給定 N 個閉區間 [ai,bi],請你在數軸上選擇盡量少的點,使得每個區間內至少包含一個選出的點。輸出選擇的點的最小數量。
思路:每個區間遲早要選出一個符合要求的點,而對於一個大區間包含小區間的情況,小區間滿足大區間一定滿足,反之不亦然,所以不妨先考慮小區間。
按右端點從小到大排序。首先考慮第一個區間,反正一定要選一個點,不妨選右端點,顯然,這樣能盡可能覆蓋較多(左端點在第一段右端點的左邊的)區間,把這個點設為pos。依次枚舉每一個區間,如果它的左端點小於等於pos,則一定已經被覆蓋了;如果他的左端點大於pos,則需要選一個新點,同理可知應該選右端點,重復上述過程即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
struct Seg {
int l, r;
}seg[N];
bool cmp(Seg a, Seg b) {
if (a.r != b.r) return a.r < b.r;
else return a.l > b.l;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> seg[i].l >> seg[i].r;
sort(seg, seg + n, cmp);
int ans = 1, pos = seg[0].r;
for (int i = 1; i < n; i++)
if (seg[i].l > pos) ans++, pos = seg[i].r;
cout << ans;
return 0;
}
AcWing 908. 最大不相交區間數量
給定 N 個閉區間 [ai,bi],請你在數軸上選擇若干區間,使得選中的區間之間互不相交(包括端點)。輸出可選取區間的最大數量。
思路:首先考慮第一個區間選哪個。按右端點從小到大排序,選擇右端點最小的區間,可以盡可能地提高選擇的余地。在數軸剩下的部分同樣這樣做即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
struct Seg {
int l, r;
} seg[N];
bool cmp(Seg a, Seg b) {
return a.r < b.r;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> seg[i].l >> seg[i].r;
sort(seg, seg + n, cmp);
int ans = 1, pos = seg[0].r;
for (int i = 1; i < n; i++)
if (seg[i].l > pos) ans++, pos = seg[i].r;
cout << ans;
return 0;
}
AcWing 906. 區間分組
給定 N 個閉區間 [ai,bi],請你將這些區間分成若干組,使得每組內部的區間兩兩之間(包括端點)沒有交集,並使得組數盡可能小。
思路:
圖書館中最少需要安排多少個座位,使得N個在不同時段[ai,bi]學習的人恰好都有座?
只要座位數大於同時學習的最大人數即可。。。(反正每個來到的人都會自動坐在空位上。。。)
我也不知道這叫啥思路,“人工智能”?
用差分+前綴和的話,數組有點大,自然想到離散化。
其實沒必要,將“坐下”和“離開”的所有操作按時間先后排序,按照時間軸依次進行(座位+1/-1)即可。
同一個時間點既有來學習的也有離開的,需要為來學習的人加一個座位。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, cnt, ans;
struct Node {
int p, op;
} node[N];
bool cmp(Node a, Node b) {
if (a.p != b.p) return a.p < b.p;
else return a.op > b.op;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> node[i*2-1].p >> node[i*2].p;
node[i*2-1].op = 1, node[i*2].op = -1;
}
sort(node + 1, node + 1 + n * 2, cmp);
for (int i = 1; i <= n * 2; i++) {
cnt += node[i].op;
ans = max(ans, cnt);
}
cout << ans;
return 0;
}
AcWing 907. 區間覆蓋
給定 N 個閉區間 [ai,bi] 以及一個線段區間 [s,t],請你選擇盡量少的區間,將指定線段區間完全覆蓋。輸出最少區間數,如果無法完全覆蓋則輸出 −1。
思路:
首先考慮覆蓋了s點的區間,顯然要選右端點最靠右的。
將所選區間的右端點當作新的s繼續操作即可。
掃一遍即可,具體實現見代碼。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int n, s, t;
struct Seg {
int l, r;
} seg[N];
bool cmp(Seg a, Seg b) {
return a.l < b.l;
}
int main() {
cin >> s >> t >> n;
for (int i = 0; i < n; i++) {
cin >> seg[i].l >> seg[i].r;
}
sort(seg, seg + n, cmp);
int pos = s, maxr = -inf, ans = 0;
for (int i = 0; i < n; i++) {
if (seg[i].l > pos) pos = maxr, ans++;
if (seg[i].l <= pos && seg[i].r >= pos && seg[i].r > maxr) {
maxr = seg[i].r;
}
if (pos >= t) break;
}
if (pos < t && maxr >= t) pos = maxr, ans++;
if (pos >= t) cout << ans;
else cout << -1;
return 0;
}