在學習動態規劃法之前,我們先來了解動態規劃的幾個概念
1、 階段:把問題分成幾個相互聯絡的有順序的幾個環節,這些環節即稱為階段。
2、 狀態:某一階段的出發位置稱為狀態。
3、 決策:從某階段的乙個狀態演變到下乙個階段某狀態的選擇。
4、 狀態轉移方程:前一階段的終點就是後一階段的起點,前一階段的決策選擇匯出了後一階段的狀態,這種關係描述了由k階段到k+1階段狀態的演變規律,稱為狀態轉移方程。
動態規劃法的定義:在求解問題中,對於每一步決策,列出各種可能的區域性解,再依據某種判定條件,捨棄那些肯定不能得到最優解的區域性解,在每一步都經過篩選,以每一步都是最優解來保證全域性是最優解,這種求解方法稱為動態規劃法。
一般來說,適合於用動態規劃法求解的問題具有以下特點:
1、可以劃分成若干個階段,問題的求解過程就是對若干個階段的一系列決策過程。
2、每個階段有若干個可能狀態
3、乙個決策將你從乙個階段的一種狀態帶到下乙個階段的某種狀態。
4、在任乙個階段,最佳的決策序列和該階段以前的決策無關。
5、各階段狀態之間的轉換有明確定義的費用,而且在選擇最佳決策時有遞推關係(即動態轉移方程)。
動態規劃法所處理的問題是乙個多階段最優化決策問題,一般由初始狀態開始,通過對中間階段決策的選擇,達到結束狀態。這些決策形成了乙個決策序列,同時確定了完成整個過程的一條活動路線。如下圖:
動態規劃設計都有著一定的模式,一般要經歷以下幾個步驟:
1、劃分階段:按照問題的時間或空間特徵,把問題分為若干個階段。
2、確定狀態:將問題發展到各個階段時所處的各種客觀情況用不同的狀態表示出來。
3、確定決策並寫出狀態轉移方程:因為決策和狀態轉移有著天然的聯絡,狀態轉移就是根據上一階段的狀態和決策來匯出本階段的狀態,所以如果確定了決策,狀態轉移方程也就可以寫出。
4、尋找邊界條件:給出的狀態轉移方程是乙個遞推式,需要乙個遞推的終止條件或邊界條件。
5、程式設計實現:動態規劃的主要難點在於理論上的設計,一旦設計完成,實現部分就會非常簡單。
根據以上的步驟設計,可以得到動態規劃設計的一般模式:
for k:=階段最小值to 階段最大值do
for i:=狀態最小值to 狀態最大值do
for j:=決策最小值to 決策最大值do
f[ik]:=min(max)
有了以上的設計模式,對於簡單的動態規劃問題,就可以按部就班地進行動態規劃設計。
例1:合唱隊形(noip2004tg)
【問題描述】n位同學站成一排,**老師要請其中的(n-k)位同學出列,使得剩下的k位同學排成合唱隊形。合唱隊形是指這樣的一種隊形:設k位同學從左到右依次編號為1, 2, …, k,他們的身高分別為t1, t2, …, tk,則他們的身高滿足t1 < t2 < … < ti , ti > ti+1 > … > tk (1 <= i <= k)。你的任務是,已知所有n位同學的身高,計算最少需要幾位同學出列,可以使得剩下的同學排成合唱隊形。
【輸入檔案】輸入檔案chorus.in的第一行是乙個整數n(2 <= n <= 100),表示同學的總數。第一行有n個整數,用空格分隔,第i個整數ti(130 <= ti <= 230)是第i位同學的身高(厘公尺)。
【輸出檔案】輸出檔案chorus.out包括一行,這一行只包含乙個整數,就是最少需要幾位同學出列。
【樣例輸入】8
186 186 150 200 160 130 197 220
【樣例輸出】 4
演算法分析:此題採用動態規劃法求解。先分別從左到右求最大上公升子串行,從右到左求最大下降子串行,再列舉中間最高的乙個人。演算法實現起來也很簡單,時間複雜度o(n^2)。
我們先考慮如何求最大上公升子串行的長度,設f1(i)為前i個同學的最大上公升子串行長度。若要求f1(i),必須先求得f1(1),f1(2),…,f1(i-1),再選擇乙個最大的f1(j)(jf1(i)=max (j邊界條件:f1(1)=1;
設f2(i)為後面n-i+1位排列的最大下降子串行長度,用同樣的方法可以得到狀態轉移方程:f2(i)=max (i有了狀態轉移方程,程式實現就非常容易了。
源程式:
vart,f1,f2:array[1..100]of byte;
i,j,n,max:integer;
begin
assign(input,'chorus.in');
reset(input); readln(n);
for i:=1 to n do begin
read(t[i]);f1[i]:=1;f2[i]:=1;
end;
close(input); max:=0;
for i:=2 to n do
for j:=1 to i-1 do begin
if (t[i]>t[j])and(f1[j]>=f1[i]) then f1[i]:=f1[j]+1;
if (t[n-i+1]>t[n-j+1])and(f2[n-j+1]>=f2[n-i+1]) then f2[n-i+1]:=f2[n-j+1]+1;
end;
for i:=1 to n do if maxassign(output,'chorus.ans');
rewrite(output);
writeln(n-max+1);
close(output);
end.
運用動態規劃法求解問題的關鍵是找出狀態轉移方程,只要找出了狀態轉移方程,問題就解決了一半,剩下的事情就是解決如何把狀態轉移方程用程式實現。
例2、乘積最大(noip2000tg)
題目大意:在乙個長度為n的數字串中插入r個乘號,將它分成r+1個部分,找出一種分法,使得這r+1個部分的乘積最大。
演算法分析:此題滿足動態規劃法的求解標準,我們把它按插入的乘號數來劃分階段,若插入k個乘號,可把問題看做是k個階段的決策問題。設f[i,k]表示在前i位數中插入k個乘號所得的最大值,a[i,j]表示從第i位到第j位所組成的自然數。用f[i,k]儲存階段k的每乙個狀態,可以得狀態轉移方程:
f[i,k]=max(k<=j<=i)
邊界值:f[j,0]=a[1,j] (1根據狀態轉移方程,我們就很容易寫出動態規劃程式:
for k:=1 to r do
for i:=k+1 to n do
for j:=k to i do
if f[i,k]源程式(略)。
近年來,涉及動態規劃的各種競賽題越來越多,每一年的noip都至少有一道題目需要用動態規劃法求解。而應用動態規劃法解題是富於技巧性和創造性的,雖然在前面的求解過程中給出了乙個解題的基本模式,但由於動態規劃題目出現的形式多種多樣,並且大部分題目表面上看不出與動態規劃的直接聯絡,只有在充分把握其思想精髓的前提下大膽聯想,多做多練才能達到得心應手,靈活運用的境界。
動態規劃法
有些問題在分解時會產生許多子問題,且分解出的自問題互相交織,因而在解這類問題時,將可能重複多次解乙個子問題。這種重複當然是不必要的,解決方法可以在解決每個子問題後把它的解 包括其子子問題的解 保留在乙個 中,若遇到求與之相同的子問題時,dp演算法又稱動態規劃,是資訊學競賽中選手必須熟練掌握的一種演算...
動態規劃法
最近遇到了一道挺有意思的演算法題 四種硬幣 1元3元4元5元 問 想要湊成n元錢最少幾枚硬幣?public class coinsgamemain fun 7,is public static void fun int k,int is i1 l min i2 if l k private stat...
動態規劃法
動態規劃的關鍵點 動態規劃演算法的兩種形式 舉乙個簡單的例子 就斐波拉契數列fibonacci fibonacci n 1 n 0 fibonacci n 1 n 1 fibonacci n fibonacci n 1 fibonacci n 2 一 首先使用遞迴版本實現這個演算法 public i...