區間動態規劃

2022-05-30 18:00:20 字數 3091 閱讀 4341

石子合併

現在有n塊石頭,多多要把這n個石頭進行合併

每一次合併,多多可以把相鄰

個石子合併到一起,得分等於兩個石頭的重量之和。

可以看出,所有的石子經過n-1次合併之後,就只剩下一堆了。多多在合併果子時總共的得分等於每次合併石頭質量之和。

求得分最少是多少,最多是多少? (n<=100)

樣例輸入#1

4

4 4 5 9

樣例輸出#1

43

54

樣例解釋#1

得分最大情況:

第一步,多多先把5和9合併,得分為14,各石子數變成:4 4 14

第二步,多多先把14和4合併,得分為18,各石子變成:4 18

各得分和為54,可以證明分數最大為54;

得分最小情況:

第一步,多多先把4和4合併,得分為8,各石子變成:8 5 9

第二步,多多先把8和5合併,得分為13,各石子變成:13 9

各得分和為43,可以證明分數最小為43;

【題解】

可以知道,這道題是經典的區間dp問題;我們設dp[i][j]為i~j中操作的最大得分(以最大為例)

這裡的sum[i,j]表示原數列中的i+i+1+.......+j的值,我們可以通過o(n^2)的預處理來求出sum

第0階段:dp[1][1],dp[2][2],dp[3][3],dp[4][4] 因為一開始還沒有合併,所以這些值應該全部為0。

第1階段:兩兩合併過程如下,其中sum(i,j)表示石頭的數量,即從i開始數j個數的和

dp[1,2]=dp[1,1]+dp[2,2]+sum[1,2];

dp[2,3]=dp[2,2]+dp[3,3]+sum[2,3];

dp[3,4]=dp[3,3]+dp[4,4]+sum[4,4];

第2階段:三三合併可以拆成兩兩合併,拆分方法有兩種,前兩個為一組或後兩個為一組

dp[1,3]=dp[1,2]+dp[3,3]+sum[1,3]或dp[1,3]=dp[1,1]+dp[2,3]+sum[1,3];取其最優

dp[2,4]=dp[2,2]+dp[3,4]+sun[2,4]或dp[2,4]=dp[2,3]+dp[3,3]+sum[2,4];取其最優

第3階段,四四合併可以拆成三三合併,拆分方法有一組,

dp[1,4]=dp[1,1]+dp[2,4]+sum[1,4]或dp[1,2]+dp[3,4]+sum[1,4]或dp[1,3]+dp[4,4]+sum[1,4]取其最優;

於是,簡單的距離後我們發現乙個事實:每乙個dp式都是由三個部分構成的(i≠j時)

dp[i,j]:dp[i,k]+dp[k+1,j]+sum[i,j](i,j需要列舉)

從而得出下面的轉移方程:

dp[i,j]:=max(dp[i,j],dp[i,k]+dp[k+1,j]+sum[i,j]);    | i<=k答案就是dp[1,n]

**實現比較簡單:

石子合併(最大得分):

uses math;

varn,i,j,len,k,a,xx,yy:longint;

sum,dp:array[

0..1000,0..1000

]of longint;

s:array[

0..1000

]of longint;

begin

readln(n);

for i:=1 to n do

begin

read(a);

s[i]:=s[i-1]+a;

end;

for i:=1 to n do

for j:=i to n do

sum[i,j]:=s[j]-s[i-1];

for i:=1 to n do dp[i,i]:=0;

for len:=1 to n do

begin

i:=0; j:=0;

while (i<=n)and(j<=n) do

begin

inc(i); j:=len+i;

for k:=i to j-1

dodp[i,j]:=max(dp[i,j],dp[i,k]+dp[k+1,j]+sum[i,j]);

end;

end;

writeln(dp[

1,n]);

end.

石子合併最小得分:

//注意

賦初值!!

uses math;

varn,i,j,len,k,a,xx,yy:longint;

sum,dp:array[

0..1000,0..1000

]of longint;

s:array[

0..1000

]of longint;

begin

readln(n);

for i:=1 to n do

begin

read(a);

s[i]:=s[i-1]+a;

end;

for i:=1 to n do

for j:=i to n do

sum[i,j]:=s[j]-s[i-1];

for i:=1 to n do

for j:=1 to n do dp[i,j]:=maxint;

for i:=1 to n do dp[i,i]:=0;

for len:=1 to n do

begin

i:=0; j:=0;

while (i<=n)and(j<=n) do

begin

inc(i); j:=len+i;

for k:=i to j-1

dodp[i,j]:=min(dp[i,j],dp[i,k]+dp[k+1,j]+sum[i,j]);

end;

end;

writeln(dp[

1,n]);

end.

動態規劃 區間

真是乙個思維巧妙的毒瘤題。因此我們直接利用上面的性質來dp.設f i j f i j f i j 表示線段按右端點排序後第i ii條,j,rj j,r j j,rj 只被覆蓋了一次的最小代價,1,rj 1,r j 1,rj 全部被覆蓋的方案數。那麼,我們需要根據上乙個線段j jj和i ii的位置關係...

區間型動態規劃

給定乙個序列 字串,進行一些操作 最後一步將序列 字串去頭 去尾 剩下的會是乙個區間 i,j 狀態自然定義為f i j 表示面對子串行 i j 時的最優性質 667.最長的回文序列 中文english 給一字串 s,找出在 s 中的最長回文子串行的長度.你可以假設 s 的最大長度為 1000.exa...

動態規劃之區間dp

動態規劃 dp 就是把把大問題轉化為乙個個小問題,然後在眾多的小問題中遞推得到這個大問題的最佳解 當然,這只是我個人對動態規劃的理解,希望有大牛來指導改正 那麼區間dp就是在區間之間進行動態規劃。那麼區間dp的典型例題就是 nyoj 15 括號配對 nyoj 737 石子合併 做區間dp的題的一般步...