码迷,mamicode.com
首页 > 编程语言 > 详细

产品排序(2015 年北大自招夏令营) (与栈相关的区间DP)

时间:2019-01-28 20:11:29      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:时间   com   time   产品   cti   vector   lin   cpp   stdout   

题面:

技术分享图片

技术分享图片

\(solution:\)

又是一道\(DP\)的好题啊!状态并不明显,需要仔细分析,而且还结合了栈的特性!

做这一类题,只要出题人有点理想,一定会在栈的性质上做点文章,所以我们尽量围绕栈的性质设置\(DP\)状态。可是栈又有什么性质呢?讲真,考场我是真没想到,好像压根就不知道有这个特性:

对于队列里\([l,r]\)范围内的数,必然存在一个最晚出栈的\(i\in[l,r]\),而我们不难发现此时\([l,i-1]\)必然比\([i+1,r]\)出栈要早一些,因为\([i+1,r]\)进栈之前\(i\)就已经进栈了,而\(i\)又是最后一个出栈的(也就是说在\(i\)进栈时栈里一定是空的!!!不然:假设还有一个\(j\)未弹出,\(i\)进栈时会在\(j上面\),那么最晚出栈的就将会是\(j\)!!!)

所以不论\([l,i-1]\)的顺序是怎样的,他们对于后面的数所产生的(时间之和)与(惩罚值之和)是确定的!!!而此时如果我们知道\([l,i-1],[i+1,r]\)的总(时间之和)与(惩罚值之和)就能知道\([l,r]\)的总(时间之和)与(惩罚值之和)。所以我们应该先用这个方法先求\([l,i-1]\)\([i+1,r]\)的最小(时间之和)与(惩罚值之和)再来得出\([l,r]\)

转移方程:

\(f[l][r]=min(f[l][r],f[l][i-1]+f[i+1][r]+(st[i-1]-st[l-1])*(sd[r]-sd[i])+(st[r]-st[l-1])*d[i])\)

其中:

  1. \(i\)是需要在\([l,r]\)内枚举的
  2. \(f[l][i-1]\)\(f[i+1][r]\)是先前就求好了的
  3. \((st[i-1]-st[l-1])*(sd[r]-sd[i])\) :这个是因为\([i+1,r]\)\([l,i-1]\)后面,所以等待的时间增加了\(([l,i-1]\)的时间总和,从而总惩罚值也要相应增加。
  4. \((st[r]-st[l-1])*d[i])\)\(i\)是最后一个出栈的,它的惩罚值要乘上整个区间的时间和

唉!现在一想明明如此浅显的道理我怎么在考场上就是想不到呢???果然还是太弱了,唉.........

\(code:\)

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define ll long long
#define db double
#define inf (ll)40000000001
#define rg register int

using namespace std;

int n;
int t[205];
int d[205];
ll st[205];
ll sd[205];
ll f[205][205];

inline int qr(){
    char ch;
    while((ch=getchar())<'0'||ch>'9');
    int res=ch^48;
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+(ch^48);
    return res;
}

int main(){
    //freopen("product.in","r",stdin);
    //freopen("product.out","w",stdout);
    n=qr();
    for(rg i=1;i<=n;++i){
        t[i]=qr(),d[i]=qr();
        st[i]=st[i-1]+t[i];
        sd[i]=sd[i-1]+d[i];
    }
    for(rg i=1;i<=n;++i)
        for(rg j=i;j<=n;++j)
            f[i][j]=i==j?t[i]*d[i]:inf;
    for(rg k=1;k<=n;++k)
        for(rg l=1;l<=n-k;++l)
            for(rg i=l,r=l+k;i<=r;++i)
                f[l][r]=min(f[l][r],f[l][i-1]+f[i+1][r]+(st[i-1]-st[l-1])*(sd[r]-sd[i])+(st[r]-st[l-1])*d[i]);
    printf("%lld\n",f[1][n]);
    return 0;
}

产品排序(2015 年北大自招夏令营) (与栈相关的区间DP)

标签:时间   com   time   产品   cti   vector   lin   cpp   stdout   

原文地址:https://www.cnblogs.com/812-xiao-wen/p/10331497.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!