HDU 4238 区间dp

来源:互联网 发布:电脑性能评估软件 编辑:程序博客网 时间:2024/05/21 10:32

题目网址:https://vjudge.net/problem/HDU-4283

ddd


题意: 有k 个男生,带有d【i】的屌丝气质,原来按照1-k 的顺序进行上台表演,然后可以将第i个人放进黑屋,黑屋是以一个栈的顺序入栈出栈;

例如: 8个人   3 6 4 6 9 12 34 4     进行这样的操作将 3,6, 4, 6, 9, 12,放入黑屋,34先上台,然后12  ,然后 9*2,然后6*3,然后4*4,然后 6*5, 然后外面的4* 6 然后3*7 最终答案是139;


思路是对于一个区间 i - j:1, 第一个元素是可以直接放到最后面的,(也就是模拟进入黑屋)

                                             ,2, 而在i - j这个区间分为A (i - k),B (k+1 - j), dp[i][j]= min(dp[i][j],dp[i][k]+dp[k+1][j]+(sum[j]-sum[k])*(k-i+1));  将A B 两个区间进行合并,

                                           

之前一直在纠结区间合并的时候 为什么不能 进行B + A,但是发现顺序已经安排好了,只能A+B 因为小黑屋的栈的进出方式,但是这样为什么还能是最优的呢,因为第一步操作,将第一个元素放到后面,所以造成了优化


#include <iostream>#include<algorithm>#include<cstdio>#include<string>#include<cstring>using namespace std;const int maxn=100+5;const int inf=0x3f3f3f3f;int dp[maxn][maxn];int s[maxn];int sum[maxn];int main(){     std::ios::sync_with_stdio(false);     int t;     int n;     cin>>t;    for(int ka=1;ka<=t;ka++)     {         cin>>n;         int res=0;         memset(sum,0,sizeof(sum));         memset(dp,inf,sizeof(dp));         for(int i=1;i<=n;i++)         {             int x;             cin>>x;             res+=x;             sum[i]=res;         }         for(int i=1;i<=n;i++)            dp[i][i]=0;         for(int l=2;l<=n;l++)         {             for(int i=1;i+l<=n+1;i++)             {                 int j=i+l-1;                 dp[i][j]=min(dp[i][j],dp[i+1][j]+(sum[i]-sum[i-1])*(j-i));//虽然这个区间不能全部拿走,但是第一个人是可以关进小屋的,                 for(int k=i;k<j;k++)                 {                     dp[i][j]= min(dp[i][j],dp[i][k]+dp[k+1][j]+(sum[j]-sum[k])*(k-i+1));                 }             }         }         printf("Case #%d: %d\n",ka,dp[1][n]);         //cout<<dp[1][n]<<endl;     }    return 0;}