切原木问题(动态规划法)

切原木问题

题目

给定一根长度为N米的原木;另有一个分段价格表,给出长度L1,L2,…Li,…Lk米所对应的价格P1,P2…Pk(Li,Pi均为正整数),求切割原木分段出售所能获得的最大收益。 例如,根据下面给出的价格表,

Li	1	2	3	4	5	6	7	8	9	10Pi	1	5	8	9	10	17	17	20	23	28

若要出售一段8米长的原木,最优解是将其切割为2米和6米的两段,这样可以获得最大收益=L2+L6=5+17=22。而若要出售一段3米长的原木,最优解是根本不要切割,直接售出。

输入格式:
首行输入N,k,紧接着第二行为k个Li(递增有序)和第三行对应的k个Pi值。 (0<N,k<1000) 。

输出格式:
对应原木的最大切割收益(题目中保证最大收益值在int范围)。

输入样例:
在这里给出一组输入。例如:

8 10
1 2 3 4 5  6  7  8  9  10
1 5 8 9 10 17 17 20 23 28

输出样例:
在这里给出相应的输出。例如:

22

答案

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int num,n;
	cin>>num>>n;
	int len[n],cost[n],dp[n];
	fill(dp,dp+n,0);
	for(int i=0;i<n;i++)
	cin>>len[i];
	for(int i=0;i<n;i++)
	cin>>cost[i];
	for(int i=0;i<n;i++)
	{
		for(int j=len[i];j<=num;j++)
		dp[j]=max(dp[j],dp[j-len[i]]+cost[i]);
	}
	cout<<dp[num];
}

参考

切原木问题 (25分) (完全背包)

material_specs = { 1: { 'length': 5.5, 'defects': [(1.0, 0.03), (2.5, 0.04)], 'cost': 18 }, 2: { 'length': 6.2, 'defects': [(0.5, 0.02), (1.8, 0.05)], 'cost': 22 }, 3: { 'length': 7.8, 'defects': [(3.0, 0.03)], 'cost': 28 } } def calculate_metrics(used_materials): """计算切割损失率和利用率""" total_raw_length = 0.0 total_pieces_length = 0.0 total_defects = 0.0 total_saw_kerf = 0.0 total_remaining = 0.0 for usage in used_materials: mat_type = usage['material_type'] specs = material_specs[mat_type] # 计算缺陷总长度 defect_total = sum(d[1] for d in specs['defects']) # 获取切割参数 cuts = usage['cuts'] num_cuts = len(cuts) pieces_total = sum(cuts) if num_cuts > 0: saw_kerf = (num_cuts - 1) * 0.005 # 锯口总损耗 else: saw_kerf = 0# 计算有效可用长度(考虑缺陷位置) defect_intervals = [(start, start + length) for start, length in specs['defects']] available_lengths = [] prev_end = 0 for start, end in defect_intervals: if prev_end < start: available_lengths.append(start - prev_end) prev_end = end if prev_end < specs['length']: available_lengths.append(specs['length'] - prev_end) effective_length = sum(available_lengths) # 计算剩余材料 consumed = pieces_total + saw_kerf if consumed <= effective_length: remaining = effective_length - consumed else: remaining = 0 pieces_total = effective_length - saw_kerf # 修正切割部件总长度,避免超可用长度 # 累加统计量 total_raw_length += specs['length'] total_pieces_length += pieces_total total_defects += defect_total total_saw_kerf += saw_kerf total_remaining += remaining # 计算指标 total_loss = total_defects + total_saw_kerf + total_remaining loss_rate = (total_loss / total_raw_length) * 100 if total_raw_length != 0 else 0 utilization = (total_pieces_length / total_raw_length) * 100 if total_raw_length != 0 else 0 return loss_rate, utilization # 示例使用(需要实际切割方案数据) sample_usage = [ { 'material_type': 1, 'cuts': [1.6, 1.6, 2.2, 2.2] # 假设切割4个部件 }, { 'material_type': 2, 'cuts': [1.8, 1.8, 2.4, 2.4] } ] loss_rate, utilization = calculate_metrics(sample_usage) print(f"切割损失率: {loss_rate:.2f}%") print(f"材料利用率: {utilization:.2f}%")
05-11
切割原木问题是计算机科学领域中的一个经典优化问题,通常用于描述如何通过最优策略将一根原木成若干段以最大化收益。这个问题可以归结为动态规划的一个典型应用场景。 ### 问题背景 假设有一根长度为 `n` 的原木,并给定一张价格表,其中列出了每一段特定长度的木材所能获得的价格。目标是从这根原木出若干段并出售它们,使得总收入最大。 例如: - 原木总长 n = 5 米; - 给出价格列表 `[p1=2, p2=5, p3=6, p4=9, p5=10]` 表示长度分别为 1、2、3、4 和 5 米的木材售价分别是 2 元、5 元、6 元、9 元和 10 元。 我们需要确定最佳分割方案以及对应的最高收入。 --- ### 解决思路 #### 动态规划求解步骤 我们用数组 `dp[i]` 来表示长度为 `i` 的原木能够得到的最大价值,则状态转移方程可以写成: ``` dp[i] = max(dp[j] + price[i-j]) (对于所有 j ∈ [1,i]) ``` 也就是说,我们将长度为 i 的原木尝试从每个位置断(或者不),然后比较哪种情况下的利润更高。 **初始条件** 设 dp[0]=0,因为如果没有任何材料的话就无赚取任何金钱。 --- ### 示例代码(Python) ```python def cut_rod(price_list, length): # 创建DP数组,默认值都初始化为0 dp = [0]*(length+1) for i in range(1,length+1): # 遍历每一个可能的杆子长度 max_val=-float('inf') # 记录当前长度下能取得的最大价值 for j in range(i): # 尝试在不同的点位进行切割 temp_value = price_list[j]+dp[i-j-1] if(temp_value>max_val): max_val=temp_value dp[i]=max_val # 更新该长度的最佳结果 return dp[length] # 测试数据 prices=[0,1,5,8,9,10,17,17,20] print("最大收益:",cut_rod(prices, len(prices)-1)) ``` 上述程序的时间复杂度为 O(),空间复杂度也为 O(n)。 --- ### 总结 切割原木问题核心在于利用动态规划的思想解决资源分配最优化任务,在实际工程应用中有广泛的应用场景如金属板材加工等类似情境都可以参照此模型构建解决方案。
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值