動態規劃(一)

2022-08-03 17:42:22 字數 1546 閱讀 9831

一、dag上的動態規劃

兩個問題:巢狀矩形和硬幣問題

1、最長路及其字典序

如何求dag中不固定起點的最長路經呢?設d(i)表示從節點i出發的最長路長度,那麼狀態轉移方程就是:

d(i) = max

其中,e是邊集。最終答案就是所有d(i)的最大值。編寫記憶化搜尋程式。

1

int dp(inti)2

字典序只是消除並列名次的方法,長度才是首要要素。選擇其中最大的d[i]對應的i,若有多個i,則選擇最小的i,保證字典序最小。接下來可以選擇d(i)=d(j)+1的人乙個j,但保證字典序最小,應選擇最小的j。

void print_ans(int

i)}

當然如果要列印所有方案,只刪除break語句是不夠的,正確方法是記錄路徑上的所有點,在遞迴結束時才一次性輸出整條路徑。

void print_allans(int i,int

sum)

for(int j=1;j<=n;j++) if(g[i][j] && d[i]==d[j]+1

)

}

2、固定終點的最長路和最短路

考慮硬幣問題,終點固定,d(i)的確切含義是從節點i出發到節點0的最長路經長度。

int dp(int

s)

由於路徑長度可以為0,且s也可為0,所以不能用d=0表示這個d值沒有算過,初始化時也不能把d全設為0,而是設定乙個負值,如memset(d,-1,sizeof(d))。

但是由於節點s不一定能到達節點0,所以要用特殊的d[s]表示無法到達,故此用乙個極小數-2^30表示不能到達,可以跟所有d的初值分開-----只需把if(ans>=0)改成if(ans!=-1)即可。

int dp(int

s)

題目要求最小最大兩個值,記憶化搜尋必須寫兩個,用遞推來寫。

min[0]=max[0]=0

;for(int i=1;i<=n;i++)

for(int i=1;i<=s;i++)

for(int j=1;j<=n;j++)

if(i>=v[j])

printf(

"%d %d\n

",min[s],max[s]);

如何輸出字典序最小的方案呢。

void print_ans(int* d,int

s)}

然後分別呼叫print_ans(min,s)和print_ans(max,s)

當然也可以直接在遞推的時候就將路徑儲存下來,列印時可以省略print_ans的迴圈,可以寫成迭代形式。

for(int i=1;i<=s;i++)    

for(int j=1;j<=n;j++)

if(i>=v[j])

if(max[i]1

)

}

void print_ans(int* d,int

s)}

動態規劃 一

在現實生活中,有一類活動的過程,由於它的特殊性,可將過程分程若干個互相聯絡的階段,在它的每一階段都需要作出決策,從而使整個過程達到最好的活動效果。當然,各個階段決策的選取不是任意確定的,它依賴於當前面臨的狀態,又印象以後的發展,當各個階段決策確定後,就組成乙個決策序列,因而也就確定了整個過程的一條活...

動態規劃(一)

動態規劃的兩種常用形式 1 遞迴型 在函式中呼叫自身 優點 直觀,容易編寫 缺點 可能會因為遞迴層數太深導致爆棧,函式呼叫帶來額外時間開銷。無法使用滾動陣列節省空間。總體來說,比遞推型慢。2 遞推型 for迴圈 效率高,有可能使用滾動陣列節省空間。有的問題只能用遞迴解決,有的問題既可以用遞迴,也可以...

動態規劃 (一)

對於動態規劃的學習總共進行了兩節課,到現在為止還是一頭霧水,雖然看懂了老師上課講的例題,但是做v judge的時候還是都不太會,我主要認為我只知道了動態規劃的基本思想,就是將乙個大的問題,分成若干個小問題,但與貪心演算法不同的是,動態規劃中的每乙個小問題之間都相互影響,在每一步都取得最優解,且在不斷...