区间DP:石子归并

题目描述 
Description

有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。

输入描述 Input Description

第一行一个整数n(n<=100)

第二行n个整数w1,w2...wn  (wi <= 100)

输出描述 Output Description

一个整数表示最小合并代价

样例输入 Sample Input

4

4 1 1 4

样例输出 
Sample Output
18

这道题可以轻松地找出状态转移方程f[i,j]:=max{f[i,k]+f[k+1,j]}+sum[i,j];

但问题是如何递推是个问题,
1:若正推,for i:=1 to n do
for j:=i to n do
这样的话,递推顺序为(1,1),(1,2),(1,3),(1,4),(2,2).....
中间还有未求的量。
2:若逆推,顺序为(n,n),(n-1,n-1),(n-1,n),(n-2,n-2)....。故应逆推。

还有一点要注意,就是当前所求的区间的前趋i,后趋j,和中间变量k有(i=j-1=k)时f[i,j]:=stone[i]+stone[j];

var num:longint;
stone:array[1..100]of integer;
i,j,k,l,n,max:longint;
sum:array[1..100,1..100]of longint;
f:array[1..100,1..100]of longint;

begin fillchar(stone,sizeof(stone),0);
fillchar(sum,sizeof(sum),0);
fillchar(f,sizeof(f),$7F);
readln(n);
for i:=1 to n do
read(stone[i]);
for i:=1 to n do
for j:=i to n do
for k:=i to j do
sum[i,j]:=sum[i,j]+stone[k];
for i:=1 to n do
f[i,i]:=0;
for i:=n downto 1 do
for j:=i to n do
for k:=i to j-1 do
if (i=k)and(k=j-1)
then begin if f[i,j]>f[i,k]+f[k+1,j]+sum[i,j]
then f[i,j]:=stone[i]+stone[j];
end
else begin if f[i,j]>f[i,k]+f[k+1,j]+sum[i,j]
then f[i,j]:=f[i,k]+f[k+1,j]+sum[i,j];
end;
writeln(f[1,n]);
end.
原文地址:https://www.cnblogs.com/spiderKK/p/4230641.html