1. 程式人生 > >python----動態規劃

python----動態規劃

ret 一個 pri num line [1] 說明 第一條 ram

不能放棄治療,每天都要進步!!

什麽時候使用動態規劃呢?

1. 求一個問題的最優解
2. 大問題可以分解為子問題,子問題還有重疊的更小的子問題
3. 整體問題最優解取決於子問題的最優解(狀態轉移方程)
4. 從上往下分析問題,從下往上解決問題
5. 討論底層的邊界問題

實例1:割繩子問題

題目:給你一根長度為n的繩子,請把繩子剪成m段 (m和n都是整數,n>1並且m>1)每段繩子的長度記為k[0],k[1],…,k[m]. 請問k[0]k[1]…*k[m]可能的最大乘積是多少?例如,當繩子的長度為8時,我們把它剪成長度分別為2,3,3的三段,此時得到的最大乘積是18.

思路:f(n)=max{f(i)f(n-i)},想發與實現是2個方法,想的時候是遞歸,實現的時候是從底層至最上面。

實現:1米最1,2米最大是2,3米最大是3,4米最大是4,依次類推,求n米的最大切割

算法復雜度O(n2)

技術分享圖片
# -*- coding: utf-8 -*
def maxCutString(length):
#這三行代表輸入的繩子長度為1,2,3時,發生切割動作,最大的乘積
        if length < 2:
                return 0
        if length == 2:
                return 1
     if length == 3:
          return 2

#繩子不斷切割,當切割到長度為1,2,3時,不能繼續切割,直接返回1,2.3
arr=[0,1,2,3]#記錄繩子長度為i時候的最大乘積arr[i] for i in range(4,length+1): maxs=0 for j in range(1,i/2+1): mult=arr[j]*arr[i-j] if maxs<mult: maxs=mult arr.append(maxs)
return arr[length] print maxCutString(8)
View Code

實例2:最大連續子項和

思路:

實現:maxtmp記錄臨時子項和,遇到的每一個數不斷累加;當maxtmp為負時,清空,從下一個數開始,從新累加;當累加的數大於maxsum時,將值賦給maxsum

復雜度:O(n)

技術分享圖片
#-*- coding: utf-8 -*
#!usr/bin/python
def maxSum(lists):
        maxsum=0
        maxtmp=0
        for i in range(len(lists)):
                if maxtmp<=0:
                        maxtmp=lists[i]
                else:
                        maxtmp+=lists[i]
                if maxtmp > maxsum:
                        maxsum=maxtmp
        return maxsum
lists=[1,3,-3,4,-6,5]
print maxSum(lists)
View Code

還有一種暴力求解,雙層遍歷,復雜度O(n2)

技術分享圖片
#-*- coding: utf-8 -*
#!usr/bin/python
def maxSum(lists):
        maxsum=0
        for i in range(len(lists)):
                maxtmp=0
                for j in range(i,len(lists)):
                        maxtmp+=lists[j]
                        if maxtmp > maxsum:
                                maxsum=maxtmp
        return maxsum
lists=[1,3,-3,4,-6,5]
print maxSum(lists)
View Code

實例3:放蘋果

把M個同樣的蘋果放在N個同樣的盤子裏,允許有的盤子空著不放,問共有多少種不同的分法?(用K表示)5,1,1和1,5,1 是同一種分法。

思路:f(m,n) =f(m,n-1)+f(m-n,n)

設f(m,n) 為m個蘋果,n個盤子的放法數目,則先對n作討論,

當n>m:必定有n-m個盤子永遠空著,去掉它們對擺放蘋果方法數目不產生影響。即if(n>m) f(m,n) = f(m,m)  

當n<=m:不同的放法可以分成兩類:

    1、有至少一個盤子空著,即相當於f(m,n) = f(m,n-1);

    2、所有盤子都有蘋果,相當於可以從每個盤子中拿掉一個蘋果,不影響不同放法的數目,即f(m,n) = f(m-n,n).

而總的放蘋果的放法數目等於兩者的和,即 f(m,n) =f(m,n-1)+f(m-n,n)

遞歸出口條件說明:

    1.當n=1時,所有蘋果都必須放在一個盤子裏,所以返回1;

2.當沒有蘋果可放時,定義為1種放法;

      遞歸的兩條路,第一條n會逐漸減少,終會到達出口n==1;

      第二條m會逐漸減少,因為n>m時,我們會return f(m,m) 所以終會到達出口m==0

技術分享圖片
#!usr/bin/python
def f(m,n):
    if (m==0 or n==1):
        return 1
    if m<n:
        return f(m,m)
    else:
        return f(m,n-1)+f(m-n,n)
lines=map(int,raw_input().strip().split())
print f(lines[0],lines[1])
View Code

實例四:青蛙跳臺階問題

1.如果青蛙可以一次跳 1 級,也可以一次跳 2 級。問要跳上第 n 級臺階有多少種跳法? 思路:f(n)=f(n-1)+f(n-2) 第n級別只能由n-1級別和第n-2級別的青蛙跳到 技術分享圖片
#-*- conding: utf-8 -*
#遞歸解法
def f(n):
    if n==1:
        return 1
    elif n==2:
        return 2
    else:
        return f(n-1)+f(n-2)
print f(8)
#自下到上解法
def f2(n):
    arr=[0,1,2]
    for i in range(3,n+1):
        tmp=arr[i-1]+arr[i-2]
        arr.append(tmp)
    return arr[n]
print f2(8)
View Code 2.如果青蛙可以一次跳 1 級,也可以一次跳 2 級,一次跳 3 級,…,一次跳 nn 級。問要跳上第 n級臺階有多少種跳法? 技術分享圖片
#.*. coding:utf-8 -*
#遞歸解法
def f(n):
    if n==1:
        return 1
    else:
        return 2*f(n-1)
print f(8)
#自下而上解法
def f2(n):
    arr=[0,1,2]
    for i in range(3,n+1):
        tmp=2*arr[i-1]
        arr.append(tmp)
    return arr[n]
print f2(8)
View Code

python----動態規劃