低價購買(動規例題)

2021-07-11 08:09:19 字數 2404 閱讀 4762

求乙個最長不下降子串行,以及這個最長不下降子串行在這個序列裡的個數(不能重複)。

對於第一問我們就只要普通的dp一下就行了,(以下將最長不下降子串行稱為最長序列)對於第二問這裡要詳細的講一下。

狀態有如下:

f[i]表示到第i個數的最長序列;

b[i]表示到第i個數的最長序列的個數;

很容易得出方程:

f[i]:=max; b[i]:=max(1<=j<=i-1,且f[j]+1=f[i]);

但是b[i]的狀態僅僅這樣就可以了嗎?

對於如下的乙個序列: 5

69 68 64 67 62

對於求最長序列我們很簡單的知道是4.那麼有多少個最長序列呢?

69 68 64 62

69 68 67 62

顯然有兩個。

那這兩個是如何得出的呢?

我們可以先注意到前4個數在b陣列裡都是1,只有第5個是2,這是為什麼呢?

先看一下陣列:

f=1 2 3 3 4

b=1 1 1 1 2

其實f[5]是由f[4]得來的(j是逆推的,從4~1),然後進行到j=3的時候,f[3]+1=f[5],也就是說f[5]也可以由f[3]得來,所以這裡就需要把b[i]加上b[j]了(簡稱為work)。

然後當把f[i]更新的時候,一定要把b[i]更新,因為你現在是以乙個新的序列結尾了,之前的一律不算了。

再舉乙個栗子: 5

69 68 67 67 62

這裡如果按照上面的演算法,則最長序列的個數為2.實際上因為題目說了不能重複最長序列,則指在i=5的時候,j=3不能加上b[j]。那這如何解決呢?——可以把當前f[i]是由哪乙個得來的標記一下,例如i=5是由j=4得來的,則a[4]——第4個數標為false,如果再遇到與a[4]相同的如a[3]就不能work了。

所以b[i]的正確狀態是:

b[i]:=max(1<=j<=i-1,且f[j]+1=f[i],bz[a[j]]);

結束後就是輸出了,如何輸出呢?這裡有乙個巧妙的處理,就是把i的取值擴到1,變為n+1,而a[n+1]=0,然後輸出f[n+1]-1,b[n+1],這有什麼好處呢?

其一:輸出f[n+1]-1這個很容易理解,這就不用再o(n)找一便最大的了,f[n+1]一定就是最大的+1,減1就是最長序列了。

其二:這裡輸出b[n+1]有什麼用呢?——我們再看乙個栗子: 8

1 2 3 4 5 6 7 8

f,b陣列的狀態如下:

f=1 1 1 1 1 1 1 1

b=1 1 1 1 1 1 1 1

輸出:1 8

b陣列的前8個都是1,可實際上最長序列的個數卻是8,但因為始終沒有滿足b陣列work的條件,所以如果這裡再算乙個n+1的話,則f[9]=2,然後在j=8的時候就會讓b陣列work了。最後就會剩下7個累加進去,1+7=8,則最後的b[n+1]就等於8了。

這樣有什麼好處?顯而易見了,這樣就可以把每乙個可能相等的最長序列做乙個最終的合併,可以得到正確的答案了、

var

i,j,k,n:longint;

a,b,f:array[0..5000] of qword;

bz:array[0..50000] of boolean;

begin

readln(n);

for i:=1

to n do

read(a[i]);//輸入

f[1]:=1;

b[1]:=1;//初始值設定

for i:=2

to n+1

dobegin

f[i]:=1;

b[i]:=1;//初值

for j:=i-1

downto1do

if (a[i]then

if f[j]+1>f[i] then//判斷當前是否可以組成「更」長的序列

begin

f[i]:=f[j]+1;

fillchar(bz,sizeof(bz),true);//這裡更新bz陣列因為新的乙個最長序列必須更新以保證bz陣列的不變,因為bz=true表示的是以相等的數時,這個位置更優,而當新的序列更新的時候前面的所有更優位置都需要重新更新。

bz[a[j]]:=false;

b[i]:=b[j];

endelse

if (f[j]+1=f[i]) and bz[a[j]] then //當這兩個條件滿足時,則這個方案既沒重複,又需累加。

begin

bz[a[j]]:=false;//這也是非常重要的更新,加上這個才能避免重複計算b[j]

b[i]:=b[i]+b[j];

end;

end;

writeln(f[n+1]-1,' ',b[n+1]);

end.

總結:這一題目比較難,而且方法不唯一,需要好好消化。

編輯距離(動規例題)

題目描述 現有字串a,b,要使得a b,有如下三 種操作 將a刪除1個字元 將a插入1個字元 將a中的乙個字元改為另乙個字元 樣例輸入 sfdqxbw gfdgw 樣例輸出 4 解釋 sfdqxbw gfdqxbw gfdxbw gfdbw gfdgw,四步。這道題因為只能操作a,就能有效避免動態規...

初學動規 例題 滑雪

本人是根據mooc大學郭煒老師得程式設計與演算法進行的個人總結 一般思路 1 把原問題轉化為若干的子問題,子問題和原問題形式相同或類似,只是規模變小了。子問題的解一旦求出 就把他儲存下來,如果再遇到就可以直接使用無需再進行計算。3 確定初始狀態 邊界狀態 的值 4 狀態轉移方程。從乙個或多個值已知狀...

方格取數(動規例題)

對於n n的乙個矩陣中有著許多數字,規定你從左上角出發,走到右下角,走兩遍,每一次走時可以取矩陣中的數字,求如何取得最大的和。這道題可以四重迴圈列舉兩條路所走到的位置。然後判斷i,j點,h,k點是由上或左得來最大值,sum i,j,h,k 表示第一條道路走到i,j點,第二條走到h,k點時的最優值,顯...