n个人,每个人第i个选中时会产生一个值,为d[k] * (i-1),问全部选这n个人的最小的值。
区间dp,d[i][j]表示[i,j]里面的产生的最小的值,计算d[i][j]时可知[i,j]有j-i+1个人,可以枚举第i个人(区间最左边的人)是第第几个被选的。若是第k个被选中,则转化为两个子问题d[i+1][i+k-1],d[i+k][j],这一步产生的值为d[i] * (k-1 ) + (sum[j] - sum[i+k-1] )*k;
记忆化大法好
#include <cstring>
#include <algorithm>
using namespace std;
int t,n,a[110],cas,d[110][110],sum[110];
int dp(int i,int j){
int & ans = d[i][j];
if(ans != 1e9) return ans;
if(i >= j ) return ans = 0;
for(int k = 1;k<=j-i+1;k++) {
ans = min(ans,dp(i+1,i+k-1)+dp(i+k,j)+a[i]*(k-1)+(sum[j]-sum[i+k-1])*k);
}
return ans;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 0;i<101;i++)for(int j = 0;j<101;j++) d[i][j] = 1e9;
memset(sum,0,sizeof(sum));
for(int i = 1;i<=n;i++){
scanf("%d",a+i);
sum[i] = sum[i-1] + a[i];
}
printf("Case #%d: %d\n",++cas,dp(1,n));
}
return 0;
}