区间DP
以“区间长度”作为DP的“阶段”,使用两个坐标(区间的左、右端点)描述每个维度。
一个状态由若干个比它更小且包含于它的区间所代表的状态转移而来。
其本质是动态规划的递归实现方法。
石子合并
把区间长度len作为DP的阶段。
用左、右端点表示DP的状态。
F[l][r]
F
[
l
]
[
r
]
表示把最初的第l堆到第r堆石子合并成一堆,需要消耗的最少体力
状态转移方程:
F[l][r]=minl<=k<r(F[l][k]+F[k+1][r])+∑i=lrAi
F
[
l
]
[
r
]
=
min
l
<=
k
<
r
(
F
[
l
]
[
k
]
+
F
[
k
+
1
]
[
r
]
)
+
∑
i
=
l
r
A
i
CODE
#include<bits/stdc++.h>
using namespace std;
int n,a[310],sum[310],f[310][310];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void init()
{
n=read();
for (int i=1;i<=n;++i)
{
a[i]=read();
sum[i]=sum[i-1]+a[i];//前缀和
}
}
void dp()
{
memset(f,10,sizeof(f));
for (int i=1;i<=n;++i)
f[i][i]=0;
for (int len=2;len<=n;++len)//阶段
for (int l=1;l<=n-len+1;++l)//状态:左端点
{
int r=l+len-1;//状态:右端点
for (int k=l;k<r;++k)//决策
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
f[l][r]+=sum[r]-sum[l-1];
}
printf("%d\n",f[1][n]);
}
int main()
{
init();
dp();
return 0;
}
断环为链
任意选择一个位置断开,复制形成2倍长度的链