http://acm.hdu.edu.cn/showproblem.php?pid=6249

题意:

给出n个区间,求选k个区间的最大区间并。

 

思路:

可能存在左端点相同的多个区间,那么此时我们肯定选右端点最大的那个区间。现在将区间按左端点排序,d[i][j]表示在1~i坐标轴范围内选择j个区间的最大区间并。

状态转移方程如下:

dp[i+1][j] = max(dp[i][j],dp[i+1][j]);      //不选的话就和上一个一样
dp[i+num][j+1] = max(dp[i][j]+num,dp[i+num][j+1]);  //选择
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 const int maxn = 2000+5;
 8 
 9 int n,m,k;
10 int dp[maxn][maxn];
11 
12 struct node
13 {
14     int l,r;
15     bool operator< (const node& rhs) const
16     {
17         return l<rhs.l;
18     }
19 }s[maxn];
20 
21 int main()
22 {
23     //freopen("in.txt","r",stdin);
24     int T;
25     int kase = 0;
26     scanf("%d",&T);
27     while(T--)
28     {
29         scanf("%d%d%d",&n,&m,&k);
30         for(int i=1;i<=m;i++)
31             scanf("%d%d",&s[i].l,&s[i].r);
32         memset(dp,0,sizeof(dp));
33         sort(s+1,s+m+1);
34         int pos = 1, num = 0;
35         for(int i=0;i<n;i++)
36         {
37             while(pos<=m && s[pos].l==i+1)
38             {
39                 num = max(num, s[pos].r - s[pos].l + 1);
40                 pos++;
41             }
42 
43             for(int j=0;j<=k;j++)
44             {
45                 dp[i+1][j] = max(dp[i][j],dp[i+1][j]);
46                 dp[i+num][j+1] = max(dp[i][j]+num,dp[i+num][j+1]);
47             }
48             if(num)   num--;  //因为左端点右移了一位,所以这里需要
49         }
50         printf("Case #%d: ",++kase);
51         printf("%d\n",dp[n][k]);
52     }
53     return 0;
54 }