DP記錄

DP記錄

https://blog.csdn.net/u013309870/article/details/75193592
DP學習心得。

鋼條問題

img

img

img

img

公式(15.1):
一個長爲10的鋼鋸條,要得到這個鋼鋸條的最優切法。有不切和切兩種可能,切了之後還有不切和切兩種可能,這是一個遞歸,直到長度爲1時不能再切,這是遞歸出口。
記r(n)爲長度爲n的鋼條的最優解。隨便切一刀,得到兩段,問題就轉化爲,r(n)=max{r(n - i) + r(i),p(n)}。這兩段中,再隨便切一刀,得到四段,直至每個小段長爲1爲止,每次切割都記錄當前價格,最後比較大小。類似於快速排序的劃分算法。即得(15.1)公式。

公式(15.2):
簡化公式,顯然,上述切割方法會有重疊,即 2 + 8 和 8 + 2的切割及其其子切割。所以簡化公式爲,每次切割後,左段不再切割,看作一個整體,右端繼續切割。即得簡化公式。

注意,圖中和上面的公式下標都從1開始


// 遞歸法 自頂向下
public int r(int[] p, int n){ 
    int optSolution= p[n - 1]; // 初始化, 對應不切的情況
    if (n == 0) {
        optSolution = 0;  // 遞歸出口
    }
    else {
        for(int i = 0; i < n; i++) {
        // (15.2)
            optSolution = Math.max(optSolution , p[i] + r(p, n - i - 1));
        }
    }
    return optSolution ;
}
// 備忘錄 自頂向下
public int func(int[] p, int n) {
    int[] memo = new int[p.length + 1];
    for(int i = 0; i < memo.length, i++) 
        memo[i] = -1;
    return cut(p, n, memo);
}
public int r(int[] p, int n, int[] memo){
    int optSolution = p[n - 1];  // 初始化,對應不切
    if(memo[n] >= 0) {  // 若已經計算過局部最優,則不用再次計算
        optSolution = memo[n];
    }
    else if(n == 0) {  // 遞歸法中的遞歸出口
        optSolution = 0;
    }
    else {
        for(int i = 0; i < n; i++) {
        // (15.2)
            optSolution = Math.max(optSolution ,  p[i] + r(p, n - i - 1, memo));
        }
    }
    // 防止下標越界,所以memo空間比p大1;
    // 更新memo
    memo[n] = optSolution ; 
    return optSolution ;
}
// 動態規劃 buttom up 從鐵棒長爲1開始,遞增,選擇當前最優解,直到長度達到題目要求。
public int cut(int[] p){
    // r數組是 初始時長爲1的鐵棒的收益最大值。
    /*
      index(下標) 0 1 2 3 4 5 6 7 8 9
    數組   p(長度) 1 2 3 4 5 6 7 8 9 10
    數組 val(價格) 1 5 5 9 ...
    數組   r(最優) 1 5 6(1+5) ...
    */
    int[] r = new int[p.length];
    for(int i = 0; i < p.length; i++) {
        int optSolution = p[i];
        for(int j = 0; j < i; j++) {
            optSolution = Math.math(q, r[i - j - 1] + p[j]);
        }
        r[i] = optSolution ;
    }
    return r[p.length - 1];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章