動態規劃之01揹包問題(含代碼C)

1.動態規劃的基本思想算法

  動態規劃算法一般用於求解具備某種最優性質的問題。其基本思想也是將待求解問題分解成若干個子問題,先求解子問題,而後從這些子問題的解獲得原問題的解。與分治法不一樣的是,適合於用動態規劃求解的問題,經分解獲得子問題每每不是互相獨立的。若用分治法來解這類問題,則分解獲得的子問題數目太多,有些子問題被重複計算了不少次。若是咱們可以保存已解決的子問題的答案,而在須要時再找出已求得的答案,這樣就能夠避免大量的重複計算,節省時間。咱們能夠用一個表來記錄全部已解的子問題的答案。無論該子問題之後是否被用到,只要它被計算過,就將其結果填入表中。這就是動態規劃法的基本思路。具體的動態規劃算法多種多樣,但它們具備相同的填表格式。 與分治法最大的差異是:適合於用動態規劃法求解的問題,經分解後獲得的子問題每每不是互相獨立的(即下一個子階段的求解是創建在上一個子階段的解的基礎上,進行進一步的求解)數組

2.動態規劃的應用場景優化

  適用動態規劃的問題必須知足最優化原理、無後效性和重疊性。spa

  a.最優化原理(最優子結構性質) 最優化原理可這樣闡述:一個最優化策略具備這樣的性質,不論過去狀態和決策如何,對前面的決策所造成的狀態而言,餘下的諸決策必須構成最優策略。簡而言之,一個最優化策略的子策略老是最優的。一個問題知足最優化原理又稱其具備最優子結構性質。code

  b.無後效性 將各階段按照必定的次序排列好以後,對於某個給定的階段狀態,它之前各階段的狀態沒法直接影響它將來的決策,而只能經過當前的這個狀態。換句話說,每一個狀態都是過去歷史的一個完整總結。這就是無後向性,又稱爲無後效性。blog

  c.子問題的重疊性動態規劃將原來具備指數級時間複雜度的搜索算法改進成了具備多項式時間複雜度的算法。其中的關鍵在於解決冗餘,這是動態規劃算法的根本目的。動態規劃實質上是一種以空間換時間的算法,它在實現的過程當中,不得不存儲產生過程當中的各類狀態,因此它的空間複雜度要大於其它的算法。圖片

3.01揹包問題建模:以下圖io

  圖片中abc三個公式詳細解析:a式表示前𝑖個物品中挑選放入承重爲0的揹包中和沒有物品放入承重爲𝑗的揹包中是相等爲0。 b式代表:若是第𝑖個物品的重量大於揹包的容量,則裝人前𝑖個物品獲得的最大價值和裝入前𝑖−1個物品獲得的最大價是相同的,即物品𝑖不能裝入揹包。 c式代表:若是第𝑖個物品的重量小於揹包的容量,則會有一下兩種狀況: (1)若是把第𝑖個物品裝入揹包,則揹包物品的價值等於第𝑖−1個物品裝入容量位𝑗−𝑊_𝑖 的揹包中的價值加上第𝑖個物品的價值𝑉_𝑖; (2)若是第𝑖個物品沒有裝入揹包,則揹包中物品價值就等於把前𝑖−1個物品裝入容量爲𝑗的揹包中所取得的價值。顯然,取兩者中價值最大的做爲把前𝑖個物品裝入容量爲𝑗的揹包中的最優解。class

4.動態規劃的時間效率爲O(nc)其中n表示物品的個數,c表示揹包的容量。空間的效率就是用於存儲二維數組的佔用空間大小,即爲O(nc).效率

5.代碼以下所示:

#include<stdio.h>
#include<cstdlib>
int V[200][200];//前i個物品裝入容量爲j的揹包中得到的最大價值
int max(int a, int b)
{
    if (a >= b)
        return a;
    else return b;
}

int KnapSack(int n, int w[], int v[], int x[], int C)
{
    int i, j;
    for (i = 0; i <= n; i++)
        V[i][0] = 0;
    for (j = 0; j <= C; j++)
        V[0][j] = 0;
    for (i = 0; i < n; i++){
        for (j = 0; j < C+1; j++){
            if (j<w[i])
                V[i][j] = V[i - 1][j];
            else
                V[i][j] = max(V[i - 1][j], V[i - 1][j - w[i]] + v[i]);
        }
    }
    j = C;
    for (i = n - 1; i >= 0; i--)
    {
        if (V[i][j]>V[i - 1][j])
        {
            x[i] = 1;
            j = j - w[i];
        }
        else
            x[i] = 0;
    }
    printf("選中的物品是:\n");
    for (i = 0; i<n; i++)
        printf("%d ", x[i]);
    printf("\n");
    for (int i = 0; i < n; i++){
        for (int j = 0; j < C+1; j++){
            printf("%d\t ", V[i][j]);
            if (j == C){
                printf("\n");
            }
        }
    }
    return V[n - 1][C];

}

int main()
{
    int s;//得到的最大價值
    int w[5] = {2,2,6,5,4};//物品的重量
    int v[5] = {6,3,5,4,6};//物品的價值
    int x[5];//物品的選取狀態
    int n = 5;
    int C=10;//揹包最大容量

    s = KnapSack(n, w, v, x, C);

    printf("最大物品價值爲:\n");
    printf("%d\n", s);
    system("pause");
    return 0;

}

 運行結果:

相關文章
相關標籤/搜索