記憶化搜尋例題

2021-10-21 19:59:12 字數 1707 閱讀 2341

例題一:乘法遊戲時間限制:1sec記憶體限制:128mb題目描述乘法遊戲是在一行牌上進行的。每一張牌包括了乙個正整數。在每乙個移動中,玩家拿出一張牌,得分是用它的數字乘以它左邊和右邊的數,所以不允許拿第1張和最後1張牌。最後一次移動後,這裡只剩下兩張牌,你的目標是使得分的和最小。例如,如果數是10 1 50 20 5,依次拿1、20、50,總分是10150+50205+10505=8000而拿50、20、1,總分是15020+1205+1015=1150。輸入輸入檔案的第一行包括牌數(3<=n<=100),第二行包括n個1-100的整數,用空格分開。輸出輸出檔案只有乙個數字:最小得分。

樣例輸入

610 1 50 50 20 5

樣例輸出

3650

這道題是乙個記憶化搜尋,分治的思想。

我們用dp[i][j]記錄從i到j區間中取出所有的數所需要的最小的代價,那麼想要求出這個區間我們可以把這乙個區間分成兩個小區間,以此類推遞迴下去

如果ed <= st + 1,就說明已經都取完了,就return 0;

為了降低複雜度,我們把dp陣列中的每個數都賦值成-1, 如果搜到了乙個st,ed,其dp[i][j]不等於-1,就說明已經有值了,就直接return dp[i][j]就可以,省的多搜幾次

然後狀態轉移方程就是dp[i][j] = min(dp[i][j],dfs(i,k) + dfs(k,j) + a[i] * a[j] * a[k])k是列舉的區間中的點,每次提前給dp[i][j]賦乙個大數就行

#include

#include

#include

using

namespace std;

int n;

int a[

101]=;

int dp[

101]

[101];

intdfs

(int st,

int ed)

return dp[st]

[ed];}

intmain()

memset

(dp,-1

,sizeof

(dp));

dfs(

1,n)

;printf

("%d"

,dp[1]

[n])

;return0;

}

接下來是方法二,這類跟區間有關的記憶化搜尋,我們可以稱為「區間dp」,當然,既然是dp,我們也可以將它改寫為一半的dp形式(迴圈語句形式)。仔細觀察,這類區間合併的方式,是由長度為len的小段,通過一次合併,合併為長度為len+1的段,從初始2個長度,一直合併到n個長度。於是,我們可以以長度為階段,列舉區間起點,區間終點可以通過起點和長度計算得到,然後列舉中間分割點,進行狀態轉移,具體實現如下:

#include

#include

using

namespace std;

int n;

int a[

10001]=

;int dp[

1001][

1001]=

;int

main()

for(

int l =

3;l <= n; l++)}

}printf

("%d"

,dp[1]

[n])

;return0;

}

動態規劃 記憶化搜尋入門例題3

例題3 這個問題直接給出了一段求函式w a,b,c 的偽 def w a,b,c if a 0or b 0or c 0 return 1elif a 20or b 20or c 20 return w 20,20,20 elif areturn w a,b,c 1 w a,b 1,c 1 w a,b...

記憶化搜尋

演算法上依然是搜尋的流程,但是搜尋到的一些解用 動態規劃 的那種思想和模式作一些儲存。一般說來,動態規劃總要遍歷所有的狀態,而搜尋可以排除一些無效狀態。更重要的是搜尋還可以剪枝,可能剪去大量不必要的狀態,因此在空間開銷上往往比動態規劃要低很多。記憶化演算法在求解的時候還是按著自頂向下的順序,但是每求...

記憶化搜尋

記憶化搜尋 演算法上依然是搜尋的流程,但是搜尋到的一些解用動態規劃的那種思想和模式作一些儲存。記憶化演算法在求解的時候還是按著自頂向下的順序,但是每求解乙個狀態,就將它的解儲存下來,以後再次遇到這個狀態的時候,就不必重新求解了。例1.題目描述 給從左至右排好隊的小朋友們分糖果,要求 1.每個小朋友都...