-
描述
-
有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
-
输入
-
有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开
输出
- 输出总代价的最小值,占单独的一行 样例输入
-
3 1 2 3 7 13 7 8 16 21 4 18
样例输出
-
9 239
-
有多组测试数据,输入到文件结束。
参考四边形优化:
http://blog.csdn.net/jaihk662/article/details/78174717
dp[i][j] = dp[i][k]+dp[k+1][j]+w[i, j]
假设现在i是固定不变的
那么方程就变成了dp[j] = dp[k]+w[k, j]符合1D/1D动态规划经典模型
可以证得它也满足四边形不等式:w(i, j)+w(i', j') <= w(i', j)+w(i, j') (i<=i'<=j'<=j)①
这样的话dp[i][j]的最优决策点k和dp[i][k-1]的最优决策点k'一定满足k>=k'
同理dp[i][j]的最优决策点k和dp[i+1][k]的最优决策点k''一定满足k<=k''
令c[i][j]为dp[i][j]的最优决策点
那么求dp[i][j]只用从c[i+1][j]枚举到c[i][j-1]即可,复杂度O(n²)
引理:
对于dp方程:dp[i][j] = dp[i][k]+dp[k+1][j]+w[i, j],假设w[i, j]满足四边形不等式①,
那么dp[i][j]也满足四边形不等式dp[i][j]+dp[i'][j']<=dp[i][j']+dp[i'][j] (i<=i'<=j'<=j)
并且c[i][j]单调,也就是c[i][j]<=c[i+1][j]<=c[i+1][j+1]
#include<stdio.h>
#include<string.h>
int dp[205][205], c[205][205], a[205], sum[205];
int main(void)
{
int n, i, j, k;
while(scanf("%d", &n)!=EOF)
{
for(i=1;i<=n;i++)
{
scanf("%d", &a[i]);
sum[i] = sum[i-1]+a[i];
}
memset(dp, 62, sizeof(dp));
for(i=1;i<=n;i++)
{
dp[i][i] = 0;
c[i][i] = i;
}
for(k=1;k<=n-1;k++)
{
for(i=1;i+k<=n;i++)
{
for(j=c[i][i+k-1];j<=c[i+1][i+k];j++)
{
if(j<=i+k-1 && dp[i][j]+dp[j+1][i+k]<dp[i][i+k])
{
dp[i][i+k] = dp[i][j]+dp[j+1][i+k];
c[i][i+k] = j;
}
}
dp[i][i+k] += sum[i+k]-sum[i-1];
}
}
printf("%d\n", dp[1][n]);
}
return 0;
}