• HDU 4283 You Are the One


    区间DP。

    我们先给人编号,从左到右编号1到n。

    对于整段区间,必然有一个人是最后上场的,假设是编号为S的最后上场,

    因为是栈维护的顺序,那么编号1至S-1这S-1个人,必然是第1--S-1个上场的(具体顺序不知),

    而编号S+1至n这些人必然是第S--n-1个上场的(具体顺序不知)。

    假设我们知道左边这些人上场的最优解与右边的人上场的最优解,

    即可推导得出在编号S最后上场的情况下的最优解。

    如何计算一段区间的最优解?可以设计区间DP,dp[i][j]表示编号i至j这群人上场的最优解。

    假设现在要得到dp[st][en]这段区间最优解,

    最优解为:min{ dp[st][s-1]+(en-st)*a[s]+dp[s+1][en]+left*(sum[en]-sum[s]) }

    其中S是枚举最后哪个人上场,left表示st--S-1区间长度

    上式中,dp[st][s-1]表示S左边编号st至s-1的人上场的最优解,(en-st)*a[s]表示S最后上场的代价,

    dp[s+1][en]+left*(sum[en]-sum[s])表示S+1--en这一段最优解。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int maxn=100+10;
    int a[maxn],sum[maxn];
    int dp[maxn][maxn];
    int T,n;
    
    void read()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    }
    
    void work()
    {
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dp[i][j]=0x7FFFFFFF;
        memset(sum,0,sizeof sum);
        for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
    
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                int st=j,en=st+i-1; if(en>n) continue;
                if(i==1) {dp[st][en]=0;continue;}
    
                for(int s=st;s<=en;s++)
                {
                    int left=s-st,right=en-s;
                    if(!left) dp[st][en]=min(dp[st][en],
                                             dp[s+1][en]+a[s]*(i-1));
    
                    else if(!right) dp[st][en]=min(dp[st][en],
                                                   dp[st][s-1]+a[s]*(i-1));
    
                    else dp[st][en]=min(dp[st][en],
                                   dp[st][s-1]+
                                   dp[s+1][en]+
                                   (i-1)*a[s]+
                                   left*(sum[en]-sum[s]));
                }
            }
        }
        printf("%d
    ",dp[1][n]);
    }
    
    int main()
    {
        int c=1;
        scanf("%d",&T);
        while(T--)
        {
            read();
            printf("Case #%d: ",c++);
            work();
        }
        return 0;
    }
  • 相关阅读:
    wordwrap:breakword与wordbreak:breakall的区别所在
    python的dir()和help()
    我理解的正则表达式
    使用 OpenPyXL 批量取消「合并单元格」并自动填充值
    清除 Python 项目生成的 __pycache__ 或 pyc 缓存文件
    ElementUI + VUE学习之rules详解
    常用css样式
    tsnode报错
    自定义一个多选框样式
    eldatepicker在type为daterange时限定,日期的结束时间必须大于起始时间
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5218584.html
Copyright © 2020-2023  润新知