1. 程式人生 > 實用技巧 >線段覆蓋一類的貪心

線段覆蓋一類的貪心

統一思路:對右端點進行排序,嘗試維護最優子結構(取最差的)

區間完全覆蓋問題

給定一個長度為m的區間,再給出n條線段的起點和終點(注意這裡是閉區間)
求最少使用多少條線段可以將整個區間完全覆蓋

  • 對右端點進行從大到小排序,每次選最小的左端點進行更新

最大不相交覆蓋

給定一個長度為m的區間和n條線段的起點和終點,
從中選取儘量多的線段,使得線段都是互不相交的

  • 對右端點進行從小到大排序,每次操作保證線段條數最多且右端點最小
  • 按右端點排序後,可以考慮DP

區間選點問題

給定一個長度為m的區間,n條線段和這n條線段上至少有多少點
整個區間內最少選擇幾個點,使其滿足每一條線段的要求.

  • 按右端點從小到大排序,如果右端點相同按左端點排序,依次加點
  • 可以對字首和陣列進行差分後差分約束系統

Luogu P2887 [USACO07NOV]Sunscreen G

有C個奶牛去晒太陽 (1 <=C <= 2500),每個奶牛各自能夠忍受的陽光強度有一個最小值和一個最大值。
奶牛就得塗抹防晒霜,防晒霜的作用是讓陽光照在身上的陽光強度固定為某個值。
給出了L種防晒霜。每種的數量和固定的陽光強度也給出來了
每個奶牛隻能抹一瓶防晒霜,最後問能夠享受晒太陽的奶牛有幾個。

  • 抽象模型:存在若干線段和若干點,每條線段只能覆蓋一個點,問最多能覆蓋多少點
    按右端點從小到大排序,每次選距離左端點最近的點(即最差情況)
#include<bits/stdc++.h>
using namespace std;

const int N=3005;
int n,m,b[N],ans;
struct A{int a,b; }a[N];
bool cmp(A i,A j) {
	return i.b<j.b;
}
set<int>s;

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) {
		scanf("%d%d",&a[i].a,&a[i].b);
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=m;i++) {
		int x,y; scanf("%d%d",&x,&y);
		b[x]+=y;
	}
	for(int i=1;i<=1000;i++){
		if(b[i]) s.insert(i);
	}
	for(int i=1;i<=n;i++) {
		auto t=s.lower_bound(a[i].a);
		if(t!=s.end()&&*t<=a[i].b) {
			b[*t]--;
			if(b[*t]==0) s.erase(t);
			ans++;
		}
	}
	printf("%d\n",ans);
	return 0;
}