動態規劃

基本思想

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

與分治法最大的差異是:適用於動態規劃求解的問題,經分解後獲得的子問題不是互相獨立的(即下一個子階段的求解是創建在上一個子階段的解的基礎上,進行進一步的求解)c++

應用場景

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

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

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

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

 

具體問題

01 揹包問題:

有編號分別爲a,b,c,d,e的五件物品,它們的重量分別是4, 6, 2, 2, 5, 1,它們的價值分別是8, 10, 6, 3, 7, 2,每件物品數量只有一個,如今給你個承重爲12的揹包,如何讓揹包裏裝入的物品具備最大的價值總和?3d

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

void dynamic(int N, int C, int* weight, int* value)
{
    int* arr = new int[C+1];
    int* prearr = new int[C+1];
    int* maxvalue = new int[N];

    for (int i=1; i<=C; i++)
    {
        prearr[i] = 0;
    }

    for (int n=0; n<N; n++)
    {
        for (int c=1; c<=C; c++)
        {
            if (weight[n] > c)
            {
                arr[c] = prearr[c];
            }
            else
            {
                arr[c] = max(prearr[c], prearr[c-weight[n]]+value[n]);
            }
        }
        maxvalue[n] = arr[C];
        for (int i=1; i<=C; i++)
        {
            prearr[i] = arr[i];
            printf("%3d  ", prearr[i]);

        }
        cout << endl;
    }
    for (int i=1; i<=C; i++)
    {
        printf("%3d  ", prearr[i]);
    }
    cout << endl;

    for (int i=N-1; i>0; i--)
    {
        if (maxvalue[i] != maxvalue[i-1])
        {
            cout << i << '\t';
        }
    }
    if (maxvalue[0] != maxvalue[1])
    {
        cout << 0 << endl;
    }

    delete[] arr;
    delete[] prearr;
    delete[] maxvalue;
}

int main()
{
    int weight[] = {4, 6, 2, 2, 5, 1};
    int value[] = {8, 10, 6, 3, 7, 2};
    dynamic(6, 12,  weight, value);

    return 0;
}

 

運行結果:blog

 

  0    0    0    8    8    8    8    8    8    8    8    8  
  0    0    0    8    8   10   10   10   10   18   18   18  
  0    6    6    8    8   14   14   16   16   18   18   24  
  0    6    6    9    9   14   14   17   17   19   19   24  
  0    6    6    9    9   14   14   17   17   19   21   24  
  2    6    8    9   11   14   16   17   19   19   21   24  
  2    6    8    9   11   14   16   17   19   19   21   24  
2       1       0

 

走臺階問題

有一座高度是10級臺階的樓梯,從下往上走,每跨一步只能向上1級或者2級臺階。一共有多少種走法。博客

分析:it

若是隻差最後一步走到第10級臺階,這時候,會出現兩種狀況:

  1. 從第9級走1步到第10級

  2. 從第8級走2步到第10級

若是咱們已經知道0到9級走法有X種,0到8級走法有Y種,那麼0到10級走法 X+Y 種

咱們把走到第n級表示爲 F(n),則

      F(10) = F(9) + F(8)

當只有1級臺階和兩級臺階,走法分別爲 1 和 2

可得:

  F(1) = 1

  F(2) = 2

  F(n) = F(n-1) + F(n-2) (n>=3)

動態規劃中包含三個重要概念:最優子結構,邊界,狀態轉移方程

其中,F(9) 和 F(8) 就是 F(10) 的最優子結構,F(1) 和 F(2) 是問題的邊界

F(n) = F(n-1) + F(n-2) 是狀態轉移方程

該祭出表格了:

臺階數 1 2 3 4 5 6 7 8 9 10
走法數 1 2 3 5 8 13 21 ...    

 

 

參考博客:

https://blog.csdn.net/wangbaochu/article/details/53099953

https://blog.csdn.net/na_beginning/article/details/62884939

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息