2021.02.06不重叠线段

这篇博客讨论了一种寻找数轴上不重叠线段最大价值和的问题。首先介绍了错误的动态规划(DP)思路,该思路由于线段排序方式导致状态转移方程存在漏洞。然后提出了正确的DP解决方案,通过按线段右端点排序确保状态转移的正确性。最后,给出了问题的代码实现,并指出当线段价值为1时,问题可以转化为贪心算法求解无重叠区间数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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无重叠区间。

``` import pandas as pd import matplotlib.pyplot as plt data1 = pd.read_excel(r"C:\Users\tengh\Desktop\3\农排灌溉、煤改电\煤改电\一般台区(200户以上)类型台区晋中市21年12月29日-22年01月05日96点数据鼓楼变采集点\煤改电用户功率.xlsx", parse_dates=["数据日期"]) data2 = pd.read_excel(r"C:\Users\tengh\Desktop\3\农排灌溉、煤改电\煤改电\一般台区(200户以上)类型台区晋中市21年12月29日-22年01月05日96点数据鼓楼变采集点\乡村居民生活用电功率.xlsx", parse_dates=["数据日期"]) # 筛选用户并处理数据类型 user1 = data1[data1["用户/台区名称"] == "程玉林(煤改电)"] user2 = data2[data2["用户/台区名称"] == "胡晋雅"] # 预处理:确保数值类型 time_columns = user1.columns[8:-1] user1[time_columns] = user1[time_columns].apply(pd.to_numeric, errors='coerce').fillna(0) user2[time_columns] = user2[time_columns].apply(pd.to_numeric, errors='coerce').fillna(0) # 合并数据 combined = ( user1.set_index("数据日期")[time_columns] .add(user2.set_index("数据日期")[time_columns], fill_value=0) .groupby(level=0).sum() ) # 绘图设置 plt.figure(figsize=(15, 8)) for date in combined.index.unique(): daily_data = combined.loc[date] plt.plot( daily_data.values.astype(float), label=date.strftime("%Y-%m-%d") ) # 以下坐标设置保持变 plt.xlabel("时间点(15分钟间隔)") plt.ylabel("总有功功率(kW)") plt.title("7×24小时功率叠加图") plt.xticks( range(0, 96, 4), [f"{i//4}:{i%4*15:02d}" for i in range(0, 96, 4)], rotation=45 ) plt.legend() plt.grid() plt.tight_layout() plt.show()```改为一条直线画七天数据
最新发布
03-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值