1. 程式人生 > >c++實現鋼條切割問題

c++實現鋼條切割問題

highlight locks 限制 問題 程序 bottom blog nbsp cnblogs

今天看了算法導論裏面的動態規劃(DP),有個有意思的問題:鋼條切割來獲取最大的收益。

書中講到了幾種求解方法,包括遞歸求解法、備忘錄DP解法、自底向上的解法以及對解的重構。
書中給出不同解法的偽碼,剛好需要練習c++,就有c++來實現DP求解鋼條切割問題。

【遞歸求解】

// 鋼條切割問題
// 自頂向下 遞歸實現

#include <iostream>
#include <time.h>

using namespace std;
int cut_rod(int len, int price_arr[]);

int main(int argc, char *argv[])
{
    clock_t start, finish;
    double duration;

    start = clock();
    int rod_len = 10;
    int p_arr[] = {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30};

    int profit = cut_rod(rod_len, p_arr);
    cout << "profit = " << profit << endl;

    finish = clock();
    duration = (double)(finish - start)/CLOCKS_PER_SEC;  // 單位 s
    cout << "time cost = " << duration * 1000 << "ms" << endl;

    return 0;
}


/* 遞歸調用 cut_rod 函數
 * input: 鋼條長度len, 單位鋼條長度價格表price_arr[]
 * output: 長度為len的鋼條的最佳收益
 *
 * 思想:
 * 1. 如果len==0,返回收益0
 * 2. 否則,把鋼條切割為左邊長度為i 和右邊長度為len-i 的兩段,
 *    長度為i的一段不在切割,收益為price_arr[i], 右邊部分繼續分解。
 * 註意:
 * 1. 程序存在訪問風險;當輸入長度大於 p_arr[]長度時,會訪問到數組之外的元素;
 *    因此程序僅對 len < sizeof(p_arr)/sizeof(int) 的數據有效;
*/
int cut_rod(int len, int price_arr[])
{
    if (len == 0)
        return 0;

    int best_profit = -100;
    for (int i = 1; i <= len; i++)
    {
        best_profit = max(best_profit, price_arr[i] + cut_rod(len-i, price_arr));
    }
    return best_profit;
}

【自底向上DP重構解】

自底向上重構解包括自底向上求解法,因此在這兒只傳重構的解法;

文章假定在鋼條長度大於10英寸時,售價仍然為30美元,這樣對輸入的鋼條長度就沒有限制<當然這很不科學>;

/* DP 解決 鋼條切割問題
 * 不僅返回長度為len的鋼條的最大收益r[],而且返回切割情況s[](重構的解)
 * 重構的解也是分析子問題的性質決定的

*/

#include <iostream>
#include <string.h>

#define rod_len 17
#define LEN rod_len + 1

using namespace std;
void extend_bottom_up_cut_rod(int len, int price_arr[], int (&r)[LEN], int (&s)[LEN]);
void print_cut_rod_solution(int len, int price_arr[], int (&r)[LEN], int (&s)[LEN]);

int main(int argc, char *argv[])
{
    int price[] = {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30};
    int r[LEN], s[LEN];
    memset(r, 0, sizeof(r));
    memset(s, 0, sizeof(s));

    print_cut_rod_solution(rod_len, price, r, s);

    return 0;
}


void extend_bottom_up_cut_rod(int len, int price_arr[], int (&r)[LEN], int (&s)[LEN])
{
    if (len == 0)
        return;

    for (int j = 1; j <= len; j++)
    {
        int p = -1000;
        for (int i = 1; i <= j; i++)  // 長度為j的鋼條,切割i
        {
            int left_price;
            if (i > 10)
                left_price = price_arr[10];
            else
                left_price = price_arr[i];

            if (p < left_price + r[j-i])
            {
                p = left_price + r[j-i];
                s[j] = i;
            }
        }
        r[j] = p;
    }
}

void print_cut_rod_solution(int len, int price_arr[], int (&r)[LEN], int (&s)[LEN])
{
    extend_bottom_up_cut_rod(len, price_arr, r, s);
    cout << len << " inch rod price is " << r[len] << endl;

    cout << "the cut order is ";
    while (len > 0)
    {
        cout << s[len] << "  ";
        len -= s[len];
    }
}

  

c++實現鋼條切割問題