题目:click me~
题意:
有n个人拍成一排要上台,每一个人都有一个diaosi值D,第i个上台的人的不满意度为。
有一个黑屋子,类似于栈(先进后出)的操作,排队的人有两种选择:
(1)、直接上台
(2)、暂时进黑屋子
要求你给他们合适的排个序,使得不满意度总和最小。
解题思路:
用区间dp,表示最小总不满意度,区间中的第i个人可以是第一个出场的,也可以是最后一个j-i+1出场,也可以在中间出场(1~j-i+1)。
不妨设他是第k个出场的,那么:
(1)、第i+1到i+k-1比i先出栈,
(2)、第i+k到j总共j-i-k+1个人在i之后出栈。
举个栗子:
有5个人先排好序:1,2,3,4,5。我要第一个人第3个出场。那么出入栈的顺序是这样的:1,2,3依次入栈,然后
3,2,1依次出栈。这样的话第一个人就是第3个出场,显然4,5在1之后再出场。
由此激动人心的时刻到了我们推出状态转移方程:
其中的意思是 后面的j-i-k+1个人在i之后出场,因此每个人的不满意度都要加上diaosi值D的k倍。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int sum[105],a[105],dp[105][105];
int main()
{
int T;
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
int n;
scanf("%d",&n);
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(int k=1;k<n;k++)
for(int i=1,j=i+k;j<=n;i++,j++)
{
dp[i][j]=9999999;
for(int d=1;d<=k+1;d++)
{
dp[i][j]=min(dp[i][j],dp[i+1][i+d-1]+dp[i+d][j]+(d-1)*a[i]+(sum[j]-sum[i+d-1])*d);
}
}
printf("Case #%d: %d\n",t,dp[1][n]);
}
}