簡單暴力到dp的優化(入門篇)

2021-08-18 21:00:46 字數 3001 閱讀 9026

上篇,我們提到,遇到問題,首先根據定義寫出笨方法,找出依賴關係(有些題這一步就不太簡單,要自己歸納關係),然後進行優化,下面,我們通過幾道此方面的經典的,較為簡單的二維題目進行講解。

開始根據題來說明:

給定陣列arr,  arr  中所有的值都為正數且不重複。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,  再給定乙個整數aim 代表要找的錢數,求組成aim 的最少貨幣數。

[舉例]

arr=[5,2,3],  aim=20。

4 張5 元可以組成20 元,其他的找錢方案都要使用更多張的貨幣,返回4。

arr=[5,2,3],  aim=0。

不用任何貨幣就可以組成0 元,返回0。

arr=[3,5],aim=2。

根本無法組成2 元,錢不能找開的情況下預設返回-1。

(你要是想貪心就貪吧,反正我不貪)

定義f(a,b)代表的是a面值及之前的貨幣,組成b元的最少張數。那f(arr[-1],aim)就是我們想求的答案。現在分析,怎樣通過前面的狀態推出結果?對於貨幣arr[-1],我們可以一張都不用,那最少張數其實就是f(arr[-2],aim),我們也可以用一張arr[-1],最少張數就可能是f(arr[-2],aim-arr[-1])+1(用之前的錢組成aim-arr[-1]元錢,然後加一張arr[-1]),同理,我們可以用兩張arr[-1],或者更多,直到下乙個就超過aim的時候。所以我們應該在所有情況中選最小的,

歸納表示式:

f(a,b)=min(f(arr[a-1],b-k*arr[a])+k),k>=0,且b-k*arr[a]>=0

當然,以前也提到過,直接遞迴我們會有大量重複計算,所以需要記下來之前的結果供我們使用。有兩個引數代表現在的狀態,所以生成二維表。

l=[[0 for i in range(len(arr))] for i in range(aim+1)]#

我們看,f(arr[a],b)和誰有關?和上一行,也就是arr[a-1]那一行的很多左邊元素有關。

所以確定打表順序,從上到下,從左到右,打表,乙個乙個打,l[a][b]=min(f(a-1,b-k*arr[a])+k),依次推出l[a][b],右下角就是答案。

但是,還是有相當多的重複計算,我們的l[a][b-arr[a]]其實就是根據除了l[a-1][b]的左邊那些元素求的的最小值

所以l[a][b]=min(l[a][b-arr[a]]+1,l[a-1][b])。

其實和左邊和上邊元素相關的揹包,還有一些別的題,都是如此。對於本物品,當前決策就是拿或不拿,以前的最優情況

l[a][b-arr[a]]l[a-1][b]已經有了。不用管的。結合當前狀態的定義,就明白了。

至此,時間優化到嚴格o(a*b),空間o(a*b),空間還能優化到o(min(a,b)),下乙個題講壓縮方法。

給乙個由數字組成的矩陣,初始在左上角,要求每次只能向下或向右移動,路徑和就是經過的數字全部加起來,求可能的最小路徑和。

1  3  5  9

8  1  3  4

5  0  6  1

8  8  4  0

路徑:1 3 1 0 6 1 0路徑和最小,返回12

生成和矩陣相同大小的二維表dp,用來記錄當前的最小路徑和

(以後也不分析暴力的時間複雜度了)

對於普遍的位置i,j,只有i-1,j和i,j-1這兩個位置可以一步走到這裡,所以

dp[i,j]=min(dp[i,j-1],dp[i-1,j])+l[i,j]

壓縮:我們發現,除了這個位置上本身的數,dp[i,j]只和dp表中左邊和上邊的值有關,所以可以生成長度為矩陣較小邊長一維表,用兩層迴圈。注意順序,從左向右打表,只有這樣,左邊的那個元素才是被更新過的,才是本行的左邊那個元素。

最左邊的dp值是直接累加的,其他位置

for i 0 to 高度:

for j 0 to 寬度

dp[j]=min(dp[j-1],dp[j])+l[i,j]

時間不變,空間優化到o(較小邊長)

題幹和第一題一樣,請返回所有的還錢方法有多少種

經過一二題,應該自己會做了。

(請記住:一般問方法的題目,只需把式子中max或者min改為sum即可)

n=int(input())

dp=[0]*(n+1)

dp[0]=1

tmp=[1,5,10,20,50,100]

for kk in tmp:

for i in range(kk,n+1):

dp[i]+=dp[i-kk]

print(dp[n])

dp 優化入門

蒟蒻學了這個忘了那個,學了那個忘了這個,於是開篇部落格總結一下 qwq 不過等我 github 部落格弄好了就不會在這裡更新了 題目描述 n 個玩具,第 i 個玩具長度為 c i 要求將玩具分成若干段,定義一段 l,r 的權值 l 為 r l sum rc k 一段長為 x 的段的費用為 x l 2...

簡單暴力到dp的優化(萌新篇)

想寫一系列文章,總結一些題目,看看解決問題 優化方法的過程到底是什麼樣子的。在數學上,斐波納契數列以如下被以 遞迴的方法定義 f 0 0,f 1 1,f n f n 1 f n 2 n 2,n n 根據定義,前十項為1,1,2,3,5,8,13,21,34,55 給定乙個正整數n,求出斐波那契數列第...

效能優化入門 記錄一次併發數從8到100的過程

目前在弄的乙個專案是乙個由spring cloud搭建的微服務專案。專案仍然處於開發階段,但是在做單元測試的時候就發現了一些介面響應速度比較。由於專案資料就是開發時的測試資料,量是非常小的,只能證明我們 寫的是非常爛的。整體的業務設計也是非常有問題的,在我做壓力測試的時候發現併發量一到某個較低的值的...