题目描述 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
数据范围及提示 Data Size & Hint
数据范围
对于40%的数据,n≤10;
对于100%的数据,n≤1000;
0<=ai,bi<=1000000
0<=ci<=1000000
解题思路:对这道题,我承认是我眼拙,在很不起眼的地方错了,花了一个下午+晚上不断地测试,输出,才看出来为什么错。平时做题还是得注意一些很细节的东西,即使思路对了,没细节也是空谈。解题思路很简单,就是动态规划。我用的是一位数组来存储最终的结果。d(i) 表示扫描到第i条线段时,在满足条件的情况下,获得的最大价值总和。很简单:假设总共有t条线段两重循环,第一重,从0--t 用i表示第i条第二重,从0-- i-1用j表示第j条然后得到max(d[j])就可以。
还有一点需要注意,就是d[i]的初始值不是0,而是seg[i].value,即该条线段的价值。代码:/* 题目描述 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 数据范围及提示 Data Size & Hint 数据范围 对于40%的数据,n≤10; 对于100%的数据,n≤1000; 0<=ai,bi<=1000000 0<=ci<=1000000 */ #include <iostream> #include <algorithm> using namespace std; struct line{ int left; int right; int value; }seg[1010]; bool cmp(line a,line b){ if(a.right < b.right){ return true; } return false; } int d[1010]; //d[i]表示扫描到第i条线段所能获得的最大值 int main(){ int t; cin>>t; for(int i=0;i<t;++i){ cin>>seg[i].left>>seg[i].right>>seg[i].value; } int ans=0; sort(seg,seg+t,cmp); for(int i=0;i<t;++i){ //我就是错在这个地方,应该排序后再对d[i]赋值!不能是在排序之前! d[i]=seg[i].value; } int max=0; for(int i=0;i<t;++i){ for(int j=0;j<i;++j){ if(seg[i].left >= seg[j].right){ if(d[j]>max){ //寻找最大值 max=d[j]; } } } d[i]+=max; if(d[i]>ans){ ans=d[i]; } max=0; //记得把max清零 } cout<<ans; return 0; }
解释一下为什么两重循环为什么是对的:为什么不会发生重叠,为什么能获得最大值?第二个问题:如果第一个问题成立,对max的操作保证了取最大值第一个问题:我们是从第一条线段,即d[0]开始的,在第二重循环里if(seg[i].left >= seg[j].right)
这个语句就已经确保了不会发生重叠。为什么呢?想一想,第一条不会重叠,第二条不会重叠,一次类推,那么第三条呢?也是没问题的。而且,我们的排序是什么?是按照右端点升值排序的,你把图画一下,你就明白为什么if(seg[i].left >= seg[j].right)
这个语句确保不会有重叠出现了