C++解决钢条切割问题【动态规划】

问题描述:

给定一根长度为 l l l 的钢条 ( l < = 10000 ) (l<=10000) (l<=10000),以及一张价格表,请计算这根钢条能卖出的最大总收益。
价格表表示为 ( l i , p i ) (l_i, p_i) (li,pi) 1 < = i < = k 1<=i<=k 1<=i<=k
不在价格表中的钢条可卖出价格为 0 0 0

思路:

根据动态规划的思想,我们可以构建一个数组 d p dp dp,其中 d p [ n ] dp[n] dp[n] 代表了当总钢条长度为 n n n 时所能卖出的最大价值,则递推式显然如下:

d p [ n ] = max ⁡ 1 < = i < = k ( p i + d p [ n − l i ] ) w h e n n > = l i dp[n] = \max_{1<=i<=k}(p_i + dp[n-l_i]) \quad when \quad n>=l_i dp[n]=1<=i<=kmax(pi+dp[nli])whenn>=li
d p [ n ] = 0 w h e n n < l i . . . k dp[n] = 0 \quad when \quad n<l_{i...k} dp[n]=0whenn<li...k

而初始化时,只需要将 d p [ 0 , . . . , m i n L e n g t h ] dp[0,\quad ...,\quad minLength] dp[0,...,minLength]设置为 0 0 0即可。

源代码:

//
//  main.cpp
//  SteelCutting
//
//  Created by 胡昱 on 2021/11/11.
//

#include <iostream>
#include <vector>
using namespace std;

class Steel{
public:
    int length;
    int value;
    Steel(int l, int v) {
        length = l;
        value = v;
    }
};

int main() {
    // 共m个问题
    int m;
    cin >> m;
    while((m--) > 0) {
        // 输入总钢条长度和价格表中不同价格的钢条的数量
        int l = 10000, c = 100;
        cin >> l >> c;
        
        // 构建动态规划数组
        // dp[i]代表了当总钢条长度为i时的最大产出价值
        int* dp = new int[l + 1];
        
        // 输入钢条长度价格表(如果长度超出了总钢条长度则不用输入)
        vector<Steel> steel;
        int length, value, minLength = 2147483647;
        for(int i = 0; i < c; ++i) {
            cin >> length >> value;
            if(length <= l) {
                
                steel.push_back(Steel(length, value));
                minLength = min(minLength, length);
            }
        }
        
        // 如果不能切出任何钢条则直接输出0
        if(steel.empty()) {
            cout << 0 << endl;
            continue;
        }
        
        // 进一步初始化动态规划数组
        for(int i = 0; i < minLength; ++i) {
            dp[i] = 0;
        }
        
        // 开始自底向上动态规划
        for(int li = minLength; li < l + 1; ++li) {
            int tempValue = 0;
            for(int i = 0; i < steel.size(); ++i) {
                if(steel[i].length <= li) {
                    tempValue = max(tempValue, steel[i].value + dp[li - steel[i].length]);
                }
            }
            dp[li] = tempValue;
        }
        
        cout << dp[l] << endl;
        delete [] dp;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值