前几天我学到了线性分区问题,这是我的代码,这个代码是对的,我不理解它背后的公式,为什么会这样,如果你能够请解释我为什么这个公式有效。
for(int i=1;i<=n;i++) {
rsq[i]=rsq[i-1]+arr[i];
}
int dp[n+1][k+1];
for(int i=0;i<=n;i++) {
for(int j=0;j<=k;j++) {
dp[i][j]=987654321;
}
}
dp[0][0]=0;
for(int i=1;i<=n;i++) {
dp[i][1]=rsq[i];
}
for(int i=1;i<=k;i++) {
dp[1][i]=arr[1];
}
for(int i=2;i<=n;i++) {
for(int j=2;j<=k;j++) {
for(int x=1;x<i;x++) {
int s=max(dp[x][j-1], rsq[i]-rsq[x]);
if(dp[i][j]>s) dp[i][j]=s;
}
}
}
cout<<dp[n][k];
提前致谢。
答案 0 :(得分:1)
遵循this解释,显然状态空间dp
的语义如下;显然arr
包含要处理的项目的大小,rsq
包含下面所需的部分金额以避免重新计算。
dp[i][j] = minimum possible cost over all partitions of
arr[1],...arr[i] into j ranges
where i in {1,...,n} and j in {1,...k} or positive
infinity if such a partition does not exist
显然在实现中987654321
用于模拟正无穷大的值。注意,在说明中,与原始问题中的实现相比,状态空间的轴被交换。根据这个定义,我们得到了状态值的以下递推关系。
dp[i,j] = min{ max{ dp[i-1,j'], sum_{i'=j'+1}^{n} arr[i']} : j' in {1,...,j} }
在实施中,上述总和在rsq
中预先计算。递归关系可以解释如下。给定dp[i-1][*]
的某些特定值的i
的所有值(这意味着项1
的所有成本值已知i-1
),所有值{{1} (对于dp[i][*]
项目最多1
),可以通过从i
到j'+1
(n'
范围从j'
到j
的所有项目获取j
,考虑所有可能性)并总结剩余项目(然后构成一个分区);对于第一项的最佳分区,使用预先计算的值。这些值的最大值是选择的成本。
直观地说,这可以看作是在任意分割点对项arr[1],...,arr[n]
进行分区。右边的项目被视为一个分区(其成本是它们的成员之和,因为它们被放在一个分区中),左边的项目被最佳地递归分区为一个分区。动态编程算法(除了部分和的预先计算之外)初始化一些基本情况,这些基本情况与将每个项目放在单个分区中相对应,并组织状态的评估顺序,使得下一个更大的值所需的所有值{始终在需要时计算第二轴的{1}}。