貪心三類區間問題方法總結 (未完)
阿新 • • 發佈:2020-09-11
區間選點問題
數軸上有N個閉區間[Ai, Bi]。取儘量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以是同一個)。
思路
1.按左端點遞增排序,如果左端點相同,就按右端點遞增排序。
2.從第一個區間的右端點開始
2. 1.如果後一個區間的左端點大於了第一個區間的右端點,就說明還不能覆蓋,答案累加一,並把右端點的覆蓋距離更新.
2. 2如果後一個區間的左端點小於第一個區間的右端點,說明可以覆蓋,再把右端點的覆蓋距離更新.
#include <cstdio> #include <algorithm> using namespace std; void read(int &x) { x = 0; int f = 1; char s = getchar(); while (s < '0' || s > '9' ) { if(s == '-') { f = -1; } s = getchar(); } while(s >= '0' && s<= '9') { x = x*10 + (s - 48); s = getchar(); } x *= f; } int n; struct node { int start, end; } q[100005]; bool cmp (node a, node b) { if (a.x == b.x) return a.y < b.y; else return a.x < b.x; } int main() { read(n); for(int i = 1;i <= n;i ++) { read(q[i].start); read(q[i].end); } sort(q+1,q+1+n,cmp); // for(int i = 1;i <= n;i ++) { // printf("\n%d %d", q[i].start, q[i].end); // } int sum,E; sum = 1,E = 1; for(int i = 2;i <= n;i ++) { if(q[i].start > q[E].end) { sum ++; E = i; } } printf("%d", sum); return 0; }
區間完全覆蓋問題
給定一個長度為m的區間,再給出n條線段的起點和終點,求最少使用多少條線段可以將整個區間完全覆蓋。
思路
1、將每一條線段按左端點遞增順序排列,如果左端點相同,按右端點遞增順序排列。
2、end表示已覆蓋到的區間右端點,在剩下的線段中找出所有左端點小於等於當前已覆蓋到的區間右端點的線段,選擇右端點最大並且大於當前已覆蓋到的區間右端點,重複以上操作直至覆蓋整個區間;
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1e6 + 5; int n, s, t, end, beg, k, ans, maxl; bool flag; struct node { int x, y; } a[MAXN]; bool cmp (node a, node b) { if (a.x == b.x) return a.y < b.y; else return a.x < b.x; } int main() { scanf ("%d %d %d", &n, &s, &t); for (int i = 1; i <= n; i++) { scanf ("%d %d", &a[i].x, &a[i].y); } sort (a + 1, a + 1 + n, cmp); end = s, beg = 0, k = 1; while (end < t) { maxl = 0; for (k = beg; k <= n && a[k].x <= end; k++) { maxl = max(maxl, a[k].y); } if (maxl > end) { end = maxl; beg = k; ans ++; } else { flag = 1; break; } } if (flag) { printf ("No Solution\n"); } else printf ("%d\n", ans); return 0; }
區間劃分問題
時間軸上有n個開區間(ai, bi),把這些區間至少劃分成多少個集合,使得每個集合中的區間兩兩沒有公共點。因為是開區間,所以(1, 2)和(2,3)可在一個集合中。