Codevs3027 线段覆盖 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

数据范围及提示 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值