题意
1~n这个区间,给定m个区间[Li, Ri],从m个区间中选k个区间使得选的区间长度和最大。
思路
与01背包背包唯一的不同是区间会重叠。嵌套的那些不要紧,把小的去掉就行了,而那些一部分重叠的就不好搞了。我们可以用r[x]表示在坐标x处向右延伸的最右端点坐标,这样可以把嵌套的去掉。然后用d(i, j)表示坐标前i个拿j个区间所构成区间的最大长度,这样就可以用刷表法去推拿了这个区间的答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2019;
int d[maxn][maxn];
int r[maxn];
int main()
{
// freopen("/Users/maoxiangsun/MyRepertory/acm/i.txt", "r", stdin);
int T;
scanf("%d", &T);
int cas = 0;
while(T--) {
int n,m,k;
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i++) r[i] = 0;
for(int i = 1; i <= m; i++) {
int _l,_r;
scanf("%d%d", &_l, &_r);
for(int j = _l; j <= _r; j++)
r[j] = max(r[j], _r);
}
memset(d,0,sizeof(d));
for(int i = 1; i <= n; i++) {
for(int j = 0; j < k; j++) {
d[i][j] = max(d[i-1][j], d[i][j]);
if(r[i]) d[r[i]][j+1]=max(d[r[i]][j+1],d[i-1][j]+r[i]-i+1);
}
}
int res = 0;
for(int i = 1; i <= n; i++) {
res = max(res, d[i][k]);
}
printf("Case #%d: %d\n", ++cas, res);
}
return 0;
}