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\n",dp[1][n]);
}

int main()
{
    int c=1;
    scanf("%d",&T);
    while(T--)
    {
        read();
        printf("Case #%d: ",c++);
        work();
    }
    return 0;
}
时间: 2024-10-16 20:27:28

HDU 4283 You Are the One的相关文章

HDU 4283 You Are the One (区间dp)

HDU 4283 题意:有n个男屌丝依次排队要登台,如果某个男屌丝前面排有k个人,则该屌丝很生气,生气程度 = (k-1)*D(D代表屌丝程度).现在有一个小黑屋,小黑屋先进后出,如果把某屌丝放进去,那么他后面的人就能先登台.给出每个人的屌丝程度与原定上台顺序,求怎样利用小黑屋,能够使众屌丝生气程度之和最小,求出最小值. 思路: #define 愤怒值 生气程度 dp[i][j]表示从第i个屌丝到第j个屌丝这段区间的min(sum(愤怒值))(假设只有这j-i+1个屌丝) 那么对于dp[i][j

HDU 4283 You Are the One 区间dp

题意: 题意好复杂... 给定n个人,从左到右排好队. 他们依次从左到右离开队伍. 每个人有个权值d 当某个人是第k-th离开队伍的,那么不开心值为 d*(k-1) 有一个操作,对于一个子序列,可以把前面一段翻转. 问最小的不开心值和. #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<vector> #include<q

HDU 4283:You Are the One(区间DP)

http://acm.hdu.edu.cn/showproblem.php?pid=4283 题意:有n个数字,不操作的情况下从左到右按顺序输出,但是可以先让前面的数字进栈,让后面的数字输出,然后栈里的数字再输出.执行完各种操作后,第i个数字输出的代价是w[i] * (i-1).问如何弄才能使得代价最小,输出. 思路:做了半个下午.好菜啊QAQ. 考虑两种情况: 1.左区间的元素先输出,然后右区间的元素再输出.这个时候方程为 dp[i][j] = dp[i][k] + dp[k+1][j] +

HDU 4283:You Are the One 区间DP好题

String painter 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4283 题意: 有n个人参加选秀,每个人有一个Di值,Di值*(出场时间-1)决定他们的悲惨度,这i个人按顺序出场,但是在出场前可以通过一个栈略微调整出场顺序,输出调整后的总悲惨度最小值. 题解: 设dp[i][j]是区间[i,j]部分的最小悲惨值和,终点状态为dp[1][n].可以发现,对于每个[i,j]区间不需要考虑 i 以前和 j 以后的部分,那么 i 就是第一个

HDU 4283 You Are the One (12年天津 区间DP)

题意:有一个队列,每个人有一个愤怒值a[i],如果他是第k个上场,不开心指数就为(k-1)*a[i].但是边上有一个小黑屋(其实就是个堆栈),可以一定程度上调整上场程序 思路:枚举区间和每个人第几个上场 dp[i][j]:[i,j]的最小分数 假设区间[i,j],第i个人第k个出场(1<=k<=j-i+1),如果第i个人第k个出场,则他之前有k-1个人出场:dp[i+1][i+k-1](应为枚举第i个人,所以从i+1开始) 然后后面剩的人又是一个子区间:dp[k+i][j]  当然在这之前有k

HDU 4283 You Are the One (区间DP,经典)

题意: 某校举行一场非诚勿扰,给定一个出场序列,表示n个人的屌丝值,如果他是第k个出场的,他的不满意度为(k-1)*diao[i].为了让所有人的屌丝值之和更小,导演设置一个栈,可以将部分人装进栈中,来改变序列.也就是说,要么按照给定序列上场,要么将某个人前面部分人装进栈,让该人先出场,再让栈中的人出场,都行.问屌丝值之和最少可以是多少? 思路: 想挫了,哎- 如果考虑区间p[1->n]的出场次序时,只考虑p[1]是第几个出场的就行了,假设是第k个,那么区间p[2->k]就必须比p[1]先出场

hdu 4283 区间dp

You Are the One Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3878    Accepted Submission(s): 1793 Problem Description The TV shows such as You Are the One has been very popular. In order to m

HDU 4283 (第k个出场 区间DP)

http://blog.csdn.net/acm_cxlove/article/details/7964594 http://www.tuicool.com/articles/jyaQ7n http://blog.csdn.net/woshi250hua/article/details/7973824 记忆化搜索(15MS): #include <iostream> #include <string> #include <cstring> #include <cs

!HDU 4283 屌丝联谊会-区间dp

题意:一群屌丝排队参加联谊,每个人都有屌丝值,如果他是第k个进场的,那么他的愤怒值就是(K-1)*Di,主办方想使所有屌丝的愤怒值总和最小,就用一个黑屋子来改变屌丝的进场顺序,黑屋子实际上是一个栈,先进后出.现在要求用这个栈能得到的最小的愤怒值总和是多少. 分析: 难点在于你不知道用了多少次黑屋子.用在哪些人身上以及每次各自进黑屋子的人数.很容易知道每个决策都会影响最终结果,那么我们就想用dp来做.问题是哪种dp,本题实际上就是在区间上求最优解,所以用区间dp.区间dp就是每次把一个区间分成两个