HDU4283 You Are the One(经典区间dp)

动态规划要从最优子结构来推出大的方案

对于本题,我们要思考,什么是大的,什么是小的。

或许有些人会想设计状态为f[i],表示我从1-i的最小花费,但是仅仅这样是不够的,因为在这之间进小黑屋的不一定要在这之间就出来,他有后效性

那么什么是没有后效性的呢,如果我们判定这个区间就是全部的大小,他没有后面还在排队了,那么这就不会产生后效影响了

所以我们对这个方程进行改换定义,定义他为f[i][j],也就是我从i-j的最小花费且不算他前面的数,也就是我每个区间都是从第一个开始的,这样就不会被别的影响了,

那我们想我们如何转移方程呢?

在我们的对状态定义之后,不难发现要用区间dp

那么f[l][r]=min(a[i]*(k-1)+f[i+1][i+k-1]+f[i+k][j]+k*(sum[j]-sum[i+k-1]))

他的意思是我第l个数我第几个走,我们发现.f[i+1][i+k-1],f[i+k][j]这两个区间都是计算过的,且题目告诉我们先进的最后出来,这样就完美的符合转移的关系

#include
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f;
int dp[102][102];
int a[105];
int sum[105];
int main(){
    int t;
    cin>>t;
    int cas=0;
    while(t--){
        cas++;
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        cin>>a[i];
        for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+a[i];
        int len=1;
        int i,j,k;
        for(i=1;i){
            for(j=i+1;j<=n;j++)
            dp[i][j]=inf;
        }
        for(len=1;len<=n;len++){
            for(i=1;i+len-1<=n;i++){
                j=len+i-1;
                for(k=1;k<=len;k++){
                    dp[i][j]=min(dp[i][j],a[i]*(k-1)+dp[i+1][i+k-1]+dp[i+k][j]+k*(sum[j]-sum[i+k-1]));
                }
            }
        }
        printf("Case #%d: %d\n",cas,dp[1][n]);
    }
    return 0;
}
View Code

 

你可能感兴趣的:(HDU4283 You Are the One(经典区间dp))