题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=737
假设dp[1][4]表示将区间1~4的石子合并所花费的代价。dp[1][4]可以划分为dp[1][1]+dp[2][4]、dp[1][2]+dp[3][4]、dp[1][3]+dp[4][4]。还可以往下继续划分。这是划分的区间层次图:
我们只需要用dp从下往上推就行了。我们可以用一个sum数组来存储一段区间内的合并代价。用k来表示分割点,尝试区间内所有可能的分割,取代价最小的那个。
转移方程:dp[begin][end]=dp[begin][k]+dp[k+1][end]+sum[end]-sum[begin-1];
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define inf 1<<30
int dp[210][210],sum[210],a[210];
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
sum[0]=0;
for(int i=1; i<=n; i++)
sum[i]=sum[i-1]+a[i];
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
if(i==j)
dp[i][j]=0;
else
dp[i][j]=inf;
}
for(int i=1; i<n; i++)//合并的次数
{
for(int begin=1; begin+i<=n; begin++)
{
int end=i+begin;
for(int k=begin; k<end; k++)
{
if(dp[begin][end]>dp[begin][k]+dp[k+1][end]+sum[end]-sum[begin-1])
dp[begin][end]=dp[begin][k]+dp[k+1][end]+sum[end]-sum[begin-1];
}
}
}
printf("%d\n",dp[1][n]);
}
return 0;
}