python----動態規劃
不能放棄治療,每天都要進步!!
什麽時候使用動態規劃呢?
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.3View Codearr=[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)
實例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----動態規劃