You Are the One
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3012 Accepted Submission(s): 1343
The next n line are n integer D1-Dn means the value of diaosi of boys (0 <= Di <= 100)
2 5 1 2 3 4 5 5 5 4 3 2 2
Case #1: 20 Case #2: 24
比较经典的一道区间DP题目,思路都是对区间进行分割。
dp[i][j]表示单独考虑从第i个人到第j个人这段区间的最小不满意度,单独考虑意味着不考虑i之前的人,即把第i个人当做第一个人。
首先考虑栈对于队列中元素的影响。我们假设不管需不需要调换顺序,每个人出队列之后必须进栈,然后再从栈中出去。这样假设第i个人从第一个出去变成第k个出去,那么
[i+1,i+k-1]这段区间的人必须比i先出去,而[i+k,j]这个区间的人必须在k后面出去,那么
dp[i][j]就会由三部分组成,
dp[i+1][i+k-1],由于第i+1个人本来就是第一个出去,所以不变
(k-1)*ds[i],第i个人变成第k个出去的不满意度
dp[i+k][j]+(sum[j]-sum[i+k-1])*k,第i+k个人原本是第一个出去,现在
变成第k+1个出去,因此他后面所有的人的不满意度都要增加
因此,最终的状态转移方程就是
dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+ds[i]*(k-1)+(sum[j]-sum[i+k-1])*k)
/*****************
功能:元素在队列中,若想出队列,需要先进栈,然后出栈,每个元素出栈的时刻会影响其不满意度,求某个策略,使
不满意度最小。
参数:元素的不满意参数
返回值:最小的不满意度
*****************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#define maxn 110
#define INF 200000000
using namespace std;
int ds[maxn];
int dp[maxn][maxn];
int sum[maxn];
void init(int n)
{
int i,j;
for(sum[0]=ds[0],i=1;i<n;i++)
{
sum[i]=sum[i-1]+ds[i];
}
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
dp[i][j]=INF;
}
int solve(int n)
{
int i,j,k;
int len;
int tmp;
init(n);
for(len=1;len<=n;len++)
{
for(i=0;i<=n-len;i++)
{
j=i+len-1;
for(k=1;k<=len;k++)
{
tmp=min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+ds[i]*(k-1)+(sum[j]-sum[i+k-1])*k);
if(tmp<dp[i][j])
dp[i][j]=tmp;
}
}
}
return dp[0][n-1];
}
int main()
{
int T,cas=0,n;
int i;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&ds[i]);
printf("Case #%d: %d\n",++cas,solve(n));
}
return 0;
}
/***********************
输入:
2
5
1
2
3
4
5
5
5
4
3
2
2
输出:
Case #1: 20
Case #2: 24
***********************/