题目描述 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
思路
动态规划的思路都差不多,用已知的状态去更新其他元素的状态,通过不断的更新和比较得到最优解。这个题有两个限制条件,一是要线段不重叠,二是要使价值和最大,线段不重叠是通过排序实现的,价值和最大是通过动态规划实现的。分别将每条线段与后面的所有符合条件的线段尝试相连,以此来更新后面线段的数据(f[i]即为第一条到第i条线段符合条件的最大价值和),最后得到最优解。
代码
#include<iostream>
#include<cstdio>
using namespace std;
int n,a[1001],b[1001],value[1001],f[1001],ans;
void change(int *x,int *y) {
int t=*x;*x=*y;*y=t;
}
void swapp(int i,int j) {
change(&a[i],&a[j]);
change(&b[i],&b[j]);
change(&value[i],&value[j]);
}
void qcsort(int left,int right) {
if(right-left<=1) {
if(a[left]>a[right]) swapp(left,right);
return;
}
int mid=(left+right)/2,l=left,r=right;
while(l!=r) {
while(l!=mid&&a[l]<=a[mid]) l++;
while(r!=mid&&a[r]>=a[mid]) r--;
if(l==mid) mid=r;else if(r==mid) mid=l;
swapp(l,r);
}
qcsort(left,mid);qcsort(mid+1,right);
return;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d%d%d",&a[i],&b[i],&value[i]);
if(a[i]>b[i]) change(&a[i],&b[i]);
}
qcsort(1,n);
for(int i=1;i<=n;i++) {
f[i]+=value[i]; ans=max(ans,f[i]);
for(int j=i+1;j<=n;j++) {
if(b[i]<=a[j]&&f[i]>f[j]) {
f[j]=f[i];
}
}
}
printf("%d",ans);
return 0;
}