题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4283
题意:给出n个人,第k个上场的人有(K-1)*D的不满度,有一个小黑屋可以用来放人(类似于堆栈,先进小黑屋的后出)来调整上台顺序,问最小的不满度。
解题思路:区间DP
求出前i个值的总和 sum[i]=d1+d2+…+di
dp[i][j]表示第i个人到第j个人之间的最小不满意度(只考虑i到j这些人)
具体解释看注释就可以
for(int k=1;k<=n-1;k++){
for(int i=1;i+k<=n;i++){
for(int j=i;j<=i+k;j++){
//整个整体都是只放在i到i+k中考虑的
//第i个人放在第j个位置出场
//那么在i到i+k这些人中,第i+1到j个人正常输出最小不满意度dp[i+1][j]就可以
//第j个位置留给i,不满意度为a[i]*(j-1)
//后i+k-j个人输出最小不满意度dp[j+1][i+k]但注意这个是相对于原来的j+1到i+k,现在放在的是i到i+k这个整体中,所以要整体加上(sum[i+k]-sum[j])*(j-i+1)
dp[i][i+k]=min(dp[i][i+k],a[i]*(j-i)+dp[i+1][j]+dp[j+1][i+k]+(sum[i+k]-sum[j])*(j-i+1));
}
}
}
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
#define inf 1e9
int t;
int n;
int a[110];
int dp[110][110];
int sum[110];
int min(int a,int b){
return a<b? a:b;
}
int main(){
cin>>t;
int c=0;
while(t--){
c++;
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
dp[i][j]=inf;
for(int k=1;k<=n-1;k++){
for(int i=1;i+k<=n;i++){
for(int j=i;j<=i+k;j++){
dp[i][i+k]=min(dp[i][i+k],a[i]*(j-i)+dp[i+1][j]+dp[j+1][i+k]+(sum[i+k]-sum[j])*(j-i+1));
}
}
}
printf("Case #%d: %d\n",c,dp[1][n]);
}
return 0;
}