首页 > 其他分享 >dp-钢条切割

dp-钢条切割

时间:2023-08-13 16:47:34浏览次数:33  
标签:10 cut 钢条 int len amount dp 切割

钢条切割

目录

问题描述

Serling公司购买长钢条,将其切割为短钢条出售。假设切割工序没有成本,不同长度的钢条的售价如下:

length 1 2 3 4 5 6 7 8 9 10
price 1 5 8 9 10 17 17 20 24 30

那么钢条切割问题就是:给定一段长度为n英尺的钢条和一个价格表为pi(i=1...n),求切割钢条方案,使得销售收益最大(单位为元)。注意:如果长度为n英尺的钢条的价格pn足够大,那么最优解就是不需要切割。

问题分析

考虑 n = 4 的情况,那么有以下几种切割方式:
1.切割为四段,长度为:1,1,1,1;总共卖41=4元。
2.切割为三段,长度为:1,1,2;总共卖2
1+15=7元。
3.切割为两段,长度为:1,3;总共卖1
1+18=9元。
4.切割为两段,长度为:2,2;总共卖2
5=10元。
5.不切割,长度为:4;总共卖1*9=9元。

长度为n的钢条,总共有 \(2^{n-1}\) 种不同的切割方案,因为长度为n的钢条,总共有 n-1 个缝隙,每个缝隙都可以选择切或不切,所以有 \(2^{n-1}\) 种不同切割方案。所以随着n增大,切割方案总数呈指数级上升,遍历是不现实的。
在这里,很容易想到,当要分析长度为n的钢条的最优解时,可以先将钢条切成两段。将长度为n的钢条随意切割的方案是 \(2^{n-1}\) 种,但是只切两段的方案只有 n-1 种,这样规避了指数级计算量。
将切成的两段,分别再当作子问题去求解,这就是如下分治策略解法。

思路及简化

自顶向下递归

CUT-ROD(p, n)
  if n == 0
      return 0
  q = -1
  for i = 1 to n
      q = max(q, p[i] + CUT-ROD(p, n-i))
  return q

带备忘录的递归

MEMOIZED-CUT-ROD(p, n)
  let r[0..n] be a new array
  for i = 0 to n
      r[i] = -1
  return MEMOIZED-CUT-ROD-AUX(p, n, r)

MEMOIZED-CUT-ROD-AUX(p, n, r)
  if r[n] >= 0
      return r[n]
  if n == 0
      q = 0
  else
      q = -1
      for i = 1 to n
          q = max(q, p[i] + MEMOIZED-CUT-ROD-AUX(p, n-i, r))
  r[n] = q
  return q

自底向上

BOTTOM-UP-CUT-ROD(p, n)
  let r[0..n] be a new array
  r[0] = 0
  for j = 1 to n
      q = -1
      for i = 1 to j
          q = max(q, p[i] + r[j-i])
      r[j] = q
  return r[n]

程序

#include <iostream>
#include <new>

#define N 10

int solve(const int price[N], int* amount, int* cut, int len);
void print_resolution(const int* amount, const int* cut, int len);

int main(int argc, char** argv) {
    int price[N]{1,5,8,9,10,17,17,20,24,30};

    int len = 50;
    // amount 存放最大金额
    int* amount = new int[len]{0};
    // cut 存放分割长度,print_resolution 中针对每个长度计算了分割方案
    int* cut = new int[len]{0};
    int ret = solve(price, amount, cut, len);
    std::cout << "len: " << len << "; result: " << ret << std::endl;

    print_resolution(amount, cut, len);


    delete[] amount;
    delete[] cut;

    return 0;
}

void print_resolution(const int* amount, const int* cut, int len) {
    // cut 中存放的分割长度不超过10,切割掉cut[i]长度后,剩余的部分需要迭代访问cut[rest]
    //   例:长度23的分割方案 = cut[22] + 剩余 = 3 + cut[22-3] = 3 + cut[19]
    //     = 3 + 10 + cut[19-10] = 3 + 10 + cut[9] = 3 + 10 + 10
    int j, rest;
    for (int i = 0; i < len; ++i) {
        std::cout << "len: " << i+1 << "; amount[i]: " << amount[i]
            << "; cut[i]: " << cut[i] << "\t";
        rest = i + 1;
        while (rest > 0) {
            j = cut[rest-1] == 0 ? rest : cut[rest-1];
            rest -= j;
            std::cout << j << " ";
        }
        std::cout << std::endl;
    }
}

int solve(const int price[N], int* amount, int* cut, int len) {
    int half, sum;
    cut[0] = 0;
    for (int i = 0; i < len; ++i) {
        if (i < N) amount[i] = price[i];
        half = (i+1) / 2;
        for (int j = 1; j <= half; ++j) {
            sum = amount[i-j] + amount[j-1];
            if (amount[i] < sum) {
                amount[i] = sum;
                cut[i] = j;
            }
        }
    }
    return amount[len-1];
}

测试:

$ g++ -o cut cut.cpp && ./cut
len: 50; result: 150
len: 1; amount[i]: 1; cut[i]: 0	1
len: 2; amount[i]: 5; cut[i]: 0	2
len: 3; amount[i]: 8; cut[i]: 0	3
len: 4; amount[i]: 10; cut[i]: 2	2 2
len: 5; amount[i]: 13; cut[i]: 2	2 3
len: 6; amount[i]: 17; cut[i]: 0	6
len: 7; amount[i]: 18; cut[i]: 1	1 6
len: 8; amount[i]: 22; cut[i]: 2	2 6
len: 9; amount[i]: 25; cut[i]: 3	3 6
len: 10; amount[i]: 30; cut[i]: 0	10
len: 11; amount[i]: 31; cut[i]: 1	1 10
len: 12; amount[i]: 35; cut[i]: 2	2 10
len: 13; amount[i]: 38; cut[i]: 3	3 10
len: 14; amount[i]: 40; cut[i]: 2	2 2 10
len: 15; amount[i]: 43; cut[i]: 2	2 3 10
len: 16; amount[i]: 47; cut[i]: 6	6 10
len: 17; amount[i]: 48; cut[i]: 1	1 6 10
len: 18; amount[i]: 52; cut[i]: 2	2 6 10
len: 19; amount[i]: 55; cut[i]: 3	3 6 10
len: 20; amount[i]: 60; cut[i]: 10	10 10
len: 21; amount[i]: 61; cut[i]: 1	1 10 10
len: 22; amount[i]: 65; cut[i]: 2	2 10 10
len: 23; amount[i]: 68; cut[i]: 3	3 10 10
len: 24; amount[i]: 70; cut[i]: 2	2 2 10 10
len: 25; amount[i]: 73; cut[i]: 2	2 3 10 10
len: 26; amount[i]: 77; cut[i]: 6	6 10 10
len: 27; amount[i]: 78; cut[i]: 1	1 6 10 10
len: 28; amount[i]: 82; cut[i]: 2	2 6 10 10
len: 29; amount[i]: 85; cut[i]: 3	3 6 10 10
len: 30; amount[i]: 90; cut[i]: 10	10 10 10
len: 31; amount[i]: 91; cut[i]: 1	1 10 10 10
len: 32; amount[i]: 95; cut[i]: 2	2 10 10 10
len: 33; amount[i]: 98; cut[i]: 3	3 10 10 10
len: 34; amount[i]: 100; cut[i]: 2	2 2 10 10 10
len: 35; amount[i]: 103; cut[i]: 2	2 3 10 10 10
len: 36; amount[i]: 107; cut[i]: 6	6 10 10 10
len: 37; amount[i]: 108; cut[i]: 1	1 6 10 10 10
len: 38; amount[i]: 112; cut[i]: 2	2 6 10 10 10
len: 39; amount[i]: 115; cut[i]: 3	3 6 10 10 10
len: 40; amount[i]: 120; cut[i]: 10	10 10 10 10
len: 41; amount[i]: 121; cut[i]: 1	1 10 10 10 10
len: 42; amount[i]: 125; cut[i]: 2	2 10 10 10 10
len: 43; amount[i]: 128; cut[i]: 3	3 10 10 10 10
len: 44; amount[i]: 130; cut[i]: 2	2 2 10 10 10 10
len: 45; amount[i]: 133; cut[i]: 2	2 3 10 10 10 10
len: 46; amount[i]: 137; cut[i]: 6	6 10 10 10 10
len: 47; amount[i]: 138; cut[i]: 1	1 6 10 10 10 10
len: 48; amount[i]: 142; cut[i]: 2	2 6 10 10 10 10
len: 49; amount[i]: 145; cut[i]: 3	3 6 10 10 10 10
len: 50; amount[i]: 150; cut[i]: 10	10 10 10 10 10

标签:10,cut,钢条,int,len,amount,dp,切割
From: https://www.cnblogs.com/minding/p/17626751.html

相关文章

  • dp-摸牌博弈
    摸牌博弈//摸牌博弈//一维排列的卡牌,其上有不同的数字,两个对手A和B依次从中摸牌//卡牌及顺序均对两人可见//每次只能从最左或最右摸牌//最终摸到的卡牌数字之和最大者获胜//两个人都绝顶聪明(两人都会选择对自己有利对对手不利的牌)#include<iostream>#include<n......
  • dp-最长回文子序列
    最长回文子序列算法导论3rd-15.2问题描述回文:palindrome,是正序和逆序完全相同的非空字符串一个字符串有许多子序列,可以通过删除某些字符而变成回文字符串,字符串“cabbeaf”,删掉‘c’、'e'、‘f’后剩下的子串“abba”就是回文字符串,也是其中最长的回文子序列。在一个给定的......
  • dp-最长公共子序列
    最长公共子序列目录最长公共子序列问题描述最长公共子序列不等于最长公共子串问题分析程序问题描述最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。一个数列,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的......
  • dp-最优二叉搜索树
    最优二叉搜索树目录最优二叉搜索树问题描述问题分析思路程序问题描述最优二叉搜索树(OptimalBinarySearchTree,OptimalBST)问题,形式化定义:给定一个n个不同关键字的已排序的序列K=<k1,k2,...,kn>(k1<k2<...<kn),用这些关键字构造一棵二叉搜索树——对每个关键字ki,都有一个概......
  • 无涯教程-Perl - readpipe函数
    描述该函数将EXPR作为命令执行。然后,将输出作为标量文本中的多行字符串返回,或者将行作为列表context中的单个元素返回。语法以下是此函数的简单语法-readpipeEXPR返回值此函数在标量context中返回String,在列表context中返回List。例以下是显示其基本用法的示例代码......
  • 斜率优化DP
    前置芝士单调队列优化DP⌈写不动数据结构呜呜呜,先来补这个⌋对于一个DP,我们想优化祂的⌈转移⌋有些题目的可选状态有以下特征需要寻找最值可选状态区间平移存在可以永久去除的多余状态感性的讲,可行性是一个滑动窗口,状态两两之间都可以⌈直接比较出优劣......
  • UDP
    UDP不像TCP创建连接时有3次握手,而是直接发送数据,不管对方是否接收到。UDP网络通信不区分客户端和服务端。 UDP收发数据的步骤1.创建UDP套接字对象2.直接发送数据3.读取数据4.关闭套接字 示例服务端1'''2UDP应该说没有服务端和客户端,只是习惯称发......
  • [MDP.Net] 平台架構
    MDP.Net將應用系統切割為:模組、隔離、平台三個分層,透過架構設計提供模組重用、參數調整、環境建置...等等面向的快速開發能力。-模組:企業的商業知識、共用的功能邏輯,在MDP.Net裡會被開發成為一個一個的「模組」,方便開發人員依照商業需求,快速組合出應用系統。-隔離:MDP.Net加......
  • [MDP.Net] 模組架構
    MDP.Net遵循三層式架構,將模組開發切割為:系統展示、領域邏輯、資料存取三個分層,減少模組對於元件、平台、框架的直接依賴,提高模組自身的內聚力。-系統展示(Presentation):與目標客戶互動、與遠端系統通訊...等等的功能邏輯,會被歸類在系統展示。例如,使用MessageBox通知使用者處理......
  • DP1
    DP1P2523[HAOI2011]Problemc从后往前考虑,容易判掉无解。启发我们计数也从后往前考虑,设\(f[i][j]\)表示考虑到\([i,n]\)的位置,确定了\(j\)个人的编号的方案数。转移枚举之前确定了多少个人、在当前位置确定多少个人即可。CF311BCatsTransport求出正好接到每只小......