【codevs】【DP】3027线段覆盖2

  

题目描述 Description

数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。

n<=1000

输入描述 Input Description

第一行一个整数n,表示有多少条线段。

接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。

输出描述 Output Description

输出能够获得的最大价值

样例输入 Sample Input

3

1 2 1

2 3 2

1 3 4

样例输出 Sample Output

4

  嘛。。。一道DP题,相比贪心的线段覆盖1,这道题又难了一点。。。

  不过思路都很相似,我们先把读入的线段按右端点从小到大排序,为什么要这样做下面解释。

  之后定义状态,dp[i]表示前i个区间,选第i个区间的最大值,那么很容易得出状态转移方程dp[i]=max{dp[j]}+w[i]。

  接下来我们来分析为什么要排序,因为要获得最大值,我们需要区间尽量的小,以容纳更多的区间,就需要以区间的右端点排序。那么程序显而易见了,先枚举i,之后枚举前i-1个区间即可。

 

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 const int maxn=1010;
 7 struct line
 8 {
 9     int l,r,w;
10 }a[maxn];
11 int n;
12 int dp[maxn];//前i个区间,选上i的最大价值 
13 bool cmp(line a,line b)
14 {
15     return a.r<b.r;
16 }
17 void read()
18 {
19     cin>>n;
20     for(int i=1;i<=n;i++)
21     {
22         scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
23     }
24     sort(a+1,a+n+1,cmp);
25 }
26 int ans=-1;
27 void work()
28 {
29     for(int i=1;i<=n;i++) dp[i]=a[i].w;
30     for(int i=1;i<=n;i++)
31     {
32         for(int j=1;j<i;j++)
33         {
34             if(a[j].r<=a[i].l)
35             {
36                 dp[i]=max(dp[i],dp[j]+a[i].w);
37             }
38         }
39         ans=max(ans,dp[i]);
40     }
41     cout<<ans;
42 }
43 int main()
44 {
45     read();
46     work();
47     return 0;
48 }

 

posted @ 2015-07-30 10:29  sajuuk  阅读(305)  评论(0编辑  收藏  举报