求解的大问题是在区间[1, n]内合并石子的最优值,石子分成两个区间[1,k][k+1,n]。不断地将大区间分成小区间。
设dpmax[i][j]表示i堆石子到j堆石子合并得到的最大分数,dpmin[i][j]表示i堆石子到j堆石子合并得到的大小分数,num[i][j]表示i堆石子到j堆石子的总数
状态转移方程:
dpmax[i][j]=max{dp[i][k]+dp[k+1][j]+num[i][j]} k在区间[i, j-1]内
dpmin[i][j]=min{dp[i][k]+dp[k+1][j]+num[i][j]} k在区间[i, j-1]内
3.初始化:dpmax[i][i]=0;dpmin[i][j]=0;就是说一堆石子没办法和相邻的石子合并
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define clr(x) memset(x,0,sizeof(x))
#define INF 0x1f1f1f1f
long long fmax[105][105];
long long fmin[105][105];
long long a[105];
long long sum[105];
long long num[105][105];
int n,i,j,len,k;
int main(){
while(scanf("%d",&n)!=EOF){
clr(sum);
clr(fmax);
memset(fmin,INF,sizeof(fmin));
int tot=0;
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
tot=tot+a[i];
sum[i]=tot;
}
for(i=1;i<=n;i++)
for(j=i;j<=n;j++){
num[i][j]=sum[j]-sum[i-1];
}
//f[i][j]=f[i+k]+f[k+1][j]+num[i][j]
for(i=1;i<=n;i++)
fmin[i][i]=0,fmax[i][i]=0;
for(len=1;len<n;len++){
for(i=1;i<=n-len;i++){
j=i+len;
for(k=i;k<j;k++){
fmax[i][j]=max(fmax[i][j],fmax[i][k]+fmax[k+1][j]+num[i][j]);
fmin[i][j]=min(fmin[i][j],fmin[i][k]+fmin[k+1][j]+num[i][j]);
}
}
}
printf("%lld %lld\n",fmin[1][n],fmax[1][n]);
}
return 0;
}