2021.02.06不重叠线段

2021.02.06不重叠线段

题目描述

给出在数轴上的n条线段的左右端点的坐标l,r和它们的价值v,请你选出若干条没有公共点的线段(端点重合也算有公共点),使得它们的价值和最大,输出最大价值和。

输入格式

第一行一个正整数n。
接下来n行,每行三个整数l,r,v分别表示一条线段的左端点,右端点和价值。l<r,v>0。

输出格式

输出一个整数表示最大价值和。

样例输入

4
1 3 4
3 5 7
5 7 3
2 6 8

样例输出

8

数据规模和约定

n<=2000
l,r,v<=1000000

思路

【错误思路】:dp

  1. 按照左端点进行排序
  2. 定义状态dp[i]:前i条线段所能求出的最大价值和
  3. 状态转移方程:dp[i] = Math.max(dp[i], dp[j]+value[i]),其中第j条线段的右端点小于第i条线段的左端点

由上述思路:

在这里插入图片描述

上图中的5号线段的dp[5] 需要 4号线段的dp[4]推出,但是,按照定义,dp[4]应该包含了3号线段,可是,由上图可见,3号线段和5号线段是重叠的,这种思路有漏洞。

【正确思路】:dp

  1. 为了不使j号线段影响dp[i](i>j),可以按照线段的右端点排序
  2. 状态定义和转移方程和上面思路一样。

这种排序方法确保了状态转移方程的严密性和正确性。

代码

	int n;
	int[][] lines;
	int[] dp = new int[10010]; 
	void test() {
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		//0:左端点	1:右端点	2:价值
		lines = new int[n][3]; 
		for(int i = 0; i < n; i++) {
			int beg = cin.nextInt();
			int end = cin.nextInt();
			int v = cin.nextInt();
			lines[i][0] = beg;
			lines[i][1] = end;
			lines[i][2] = v;
		}
		Arrays.sort(lines, new Comparator<int[]>() {
			public int compare(int[] l1, int[] l2) {
				//右端点升序-->左端点升序
				return l1[1] != l2[1] ? l1[1]-l2[1] : l1[0]-l2[0];
			}
		});
		dp[0] = lines[0][2];
		for(int i = 1; i < n; i++) {
			int v = lines[i][2]; //此线段的价值
			dp[i] = Math.max(dp[i-1], v);
			for(int j = 0; j < i; j++) {
				if(lines[j][1] < lines[i][0]) 
					dp[i] = Math.max(dp[i], dp[j]+v);
			}
		}
		System.out.println(dp[n-1]);
	}

PS:如果每条线段的价值为1,那么可以转换为 最多能选取多少条不重叠线段。此时可以用贪心算法,见2021.5.11无重叠区间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值