标签:
题目描述 Description数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。
n<=1000
输入描述 Input Description第一行一个整数n,表示有多少条线段。
接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。
输出描述 Output Description输出能够获得的最大价值
样例输入 Sample Input3
1 2 1
2 3 2
1 3 4
样例输出 Sample Output4
嘛。。。一道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 }
标签:
原文地址:http://www.cnblogs.com/sajuuk/p/4688476.html