You Are the One
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 939 Accepted Submission(s): 446
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
该文转自:http://blog.csdn.net/woshi250hua/article/details/7973824
题目大意:给定一个序列,序列内的人有屌丝值Di,是第然后将这个序列进栈,第i个人如果是第k个出栈,那么最后的屌丝总值增加Di * (k-1), 求一个出栈序列使得总屌丝值最小。
解题思路:2012年天津网赛的1006题,当时不会做,因为一直想着记录栈里面的状态,也就是谁谁谁在栈里面,然后就想着用bitset什么的,然后就没有然后了.
言归正传,本题的模型是求一个合法的出栈序列使得屌丝总值最小,需要用区间DP解决之。合法的出栈序列中有一个很重要的性质:[1,n]这是一开始的所有元素,当1第k个出栈时[2,k]肯定比1先出栈,[k+1,n]肯定比1后出栈,正因为只要1才能第k个出栈.。这样一个区间划分成两个子区间[2,k],[k+1,n],就这样递归下去只到区间长度为1.而区间DP正是解决这类区间划分问题的利器,其实区间DP也就是一种思想啦。
区间DP一般有两种写法,三个for循环或者记忆化搜索,个人觉得记忆化搜索虽然效率低点,但是写起来相当优美。
本题我写的for循环写法是参照cxlove的写法,把当前选择对后续选择的影响给提前计算了,这也是区间Dp经常用到的技巧。而记忆化搜索写法在搜索的过程中都只考虑当前的影响,因为多了一维,所以可以这样,如果开两维,就必须将后续影响考虑在内了.
测试数据:
InPut:
10
5
1 2 3 4 5
5
5 4 3 2 2
100
41 67 34 0 69 24 78 58 62 64 5 45 81 27 61 91 95 42 27 36 91 4 2 53 92 82 21 16
18 95 47 26 71 38 69 12 67 99 35 94 3 11 22 33 73 64 41 11 53 68 47 44 62 57 37
59 23 41 29 78 16 35 90 42 88 6 40 42 64 48 46 5 90 29 70 50 6 1 93 48 29 23 84
54 56 40 66 76 31 8 44 39 26 23 37 38 18 82 29 41
OutPut:
Case #1: 20
Case #2: 24
Case #3: 170975
#include<stdio.h>
#include<string.h>
#define INF 0xffffff
int a[105],sum[105],dp[105][105];
int MIN(int a,int b){ return a<b?a:b; }
int main()
{
int T=1,t,i,j,k,l,n,temp;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(sum[0]=0,i=1;i<=n;i++)
{
scanf("%d",a+i);
sum[i]=sum[i-1]+a[i];
}
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
dp[i][j]=INF;
for(l=1;l<n;l++)
{
for(i=1;i<=n-l;i++)
{
j=i+l;
for(k=i;k<=j;k++)
{
temp=dp[i+1][k]+dp[k+1][j]+a[i]*(k-i)+(sum[j]-sum[k])*(k-i+1);
dp[i][j]=MIN(dp[i][j],temp);
}
}
}
printf("Case #%d: %d\n",T++,dp[1][n]);
}
return 0;
}