题意:中文题。不说了。

注意一些地方,机器的执行过程是没有顺序的,而且每个机器可以用多次。第一次执行的机器不消耗转移时间K。

用dp[i][j]表示第i个机器完成第j个步骤的最短时间,sum[j][i]表示第i个机器完成前j个步骤的时间。

比较容易想到一个朴素的状态转移方程:

dp[i][j]=min{dp[k][j']+sum[j][i]-sum[j'][i]}+K  (j-j'<l),(i!=k)

这里状态是O(n*m),转移是O(n*l),一定会超时,需要优化。

方程变形得dp[i][j]=min{dp[k][j']-sum[j'][i]}+sum[j][i]+K

在这里如果把k和i看作常数,那么dp[k][j']-sum[j'][i]是一个只和j'量。由于k和i比较小,我们完全可以枚举k和i的所有情况,我们定义该量为opt[i][k],我们只需要维护j-l到j这段范围内这个量的最小值即可。这里使用二维的优先队列来解决。转移部分优化成O(n)。总时间可以接受。

笔者曾经一度被初始化部分卡住,所以这里着重解释一下初始化部分的写法。

当j=1时,j唯一可能转移而来的状态就是j=0,所以首先我们要在队列里存入所有队列里存入j=0的下标,但这样还不够,还要更新j=0的状态,j=0时opt[i][k]这个变量是等于0,所以对应opt[i][k]=dp[k][0]+sum[0][i],需要把dp[k][0]和sum[0][i]都初始化为0。其他情况下,dp[i][j]都初始化为INF。

可以这么写:

    memset(dp,0x7f,sizeof(dp));
    ; i<=n; ++i)
        dp[i][]=;
    ; i<=n; ++i)
        ; j<=n; ++j)
            dq[i][j].push_back();

或者是下标j从0开始枚举,这样就包含了将j=0存入队列的部分,而初始化j=0的状态还是要自己来写。

维护队首和队尾的部分,要一次性全部完成,不能一次维护一个。

最后要注意的一个地方就是第一个机器是不花费转移机器的时间的,所以时间里要减去一个K。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<string>
#include<vector>
#include<deque>
using namespace std;
][];
][];
deque<][];
int calc(int i,int j,int k)
{
    return dp[k][j]-time[j][i];
}
int main()
{
    int m,n,K,l;
    scanf("%d%d%d%d",&m,&n,&K,&l);
    ; i<=n; ++i)
    {
        ; j<=m; ++j)
        {
            int t;
            scanf("%d",&t);
            time[j][i]=time[j-][i]+t;
        }
    }
    int ans=0x7fffffff;
    memset(dp,0x7f,sizeof(dp));
    ; i<=n; ++i)
        dp[i][]=;
    ; j<=m; ++j)
    {
        ; i<=n; ++i)
            ; k<=n; ++k)
                if(i!=k) while(!dq[i][k].empty()&&(j-dq[i][k].front())>l) dq[i][k].pop_front();
        ; i<=n; ++i)
            ; k<=n; ++k)
                if(i!=k)
                {
                    ,b=;
                    if(!dq[i][k].empty()) a=calc(i,dq[i][k].front(),k);
                    b=time[j][i]+K;
                    dp[i][j]=min(dp[i][j],a+b);
                }
        ; i<=n; ++i)
            ; k<=n; ++k)
                if(i!=k)
                {
                    while(!dq[i][k].empty()&&(calc(i,dq[i][k].back(),k)>=calc(i,j,k))) dq[i][k].pop_back();
                    dq[i][k].push_back(j);
                }
    }
    ; i<=n; ++i)
        ans=min(ans,dp[i][m]);
    printf("%d\n",ans-K);
    ;
}

Vijos 1243 生产产品 (单调队列优化的动态规划)的更多相关文章

  1. vijos 1243 生产产品 DP + 单调队列优化

    LINK 题意:有1个产品,m个步骤编号为1~m.步骤要在n个机器人的手中生产完成.其中,第i个步骤在第j个机器人手中的生产时间给定为$T[i][j]$,切换机器人消耗cost.步骤必须按顺序,同一个 ...

  2. vijos 1243 生产产品

    貌似两年前联赛复习的时候就看过这题 然而当时大概看看了 感觉太难 便没有去做 如今再去做的时候 发现其实也并不容易 ------------------------------------------ ...

  3. vijos P1243 生产产品(单调队列+DP)

      P1243生产产品   描述 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产 品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器 ...

  4. BestCoder Round #89 02单调队列优化dp

    1.BestCoder Round #89 2.总结:4个题,只能做A.B,全都靠hack上分.. 01  HDU 5944   水 1.题意:一个字符串,求有多少组字符y,r,x的下标能组成等比数列 ...

  5. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  6. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  7. [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)

    DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...

  8. UESTC 880 生日礼物 --单调队列优化DP

    定义dp[i][j]表示第i天手中有j股股票时,获得的最多钱数. 转移方程有: 1.当天不买也不卖: dp[i][j]=dp[i-1][j]; 2.当天买了j-k股: dp[i][j]=max(dp[ ...

  9. poj 1821 Fence 单调队列优化dp

    /* poj 1821 n*n*m 暴力*/ #include<iostream> #include<cstdio> #include<cstring> #incl ...

随机推荐

  1. 关于http响应内容压缩的一点小积累。

    1.在tomcat的server.xml配置文件中,添加上背景颜色为绿色的配置,服务器就会自动压缩 <Connector port="80" maxHttpHeaderSiz ...

  2. Python 练习 21

    #!/usr/bin/python # -*- coding: UTF-8 -*- h = 0 leap = 1 from math import sqrt from sys import stdou ...

  3. C++继承与派生(原理归纳)

    1.   C++继承与java不同,java遵循单继承,但java的接口为其不足做了很好的弥补了. C++则是灵活的多,为多继承.即一个C++类可以同时继承N个类的属性. 2. 对于继承方式 : 有三 ...

  4. Linux GDB常用命令一栏

    Linux GDB 常用命令如下: 1.启动和退出gdb (1)启动:gdb ***:显示一段版权说明: (*** 表示可执行程序名) (2)退出:quit.有的时候输入quit后会出现相关提示:类似 ...

  5. 自动发牌(C#版)

    利用数组实现发牌过程 一副牌去掉大小王,还剩52张.一共东.南.西.北四家,每家随机发13张牌. 提示: 东.南.西.北四家用一维数组表示 每家的牌采用一维数组表示(13张)  花色:enum Sui ...

  6. C++编程中const和#define的区别

    (1) 编译器处理方式不同 define宏是在预处理阶段展开. const常量是编译运行阶段使用.(2) 类型和安全检查不同 define宏没有类型,不做任何类型检查,仅仅是展开. const常量有具 ...

  7. 伪静态<-> 动态页,伪静态,真静态的比较和选择

    动态页,伪静态,真静态优缺点的比较 动态页不利于SEO优化. 动态页常常因为传参数的缘故后面会带一连串的问号.而搜索引擎会因为里面问号导致死循(机器人陷阱Spidertraps),所以带问号的地址搜索 ...

  8. Linux中Matlab保存多个数据到同一个文件当中

    % load pyrim % NumTrain = 50; % load machine %NumTrain = 150; % load housing % NumTrain = 300; % loa ...

  9.  BP神经网络

     BP神经网络基本原理 BP神经网络是一种单向传播的多层前向网络,具有三层或多层以上的神经网络结构,其中包含输入层.隐含层和输出层的三层网络应用最为普遍. 网络中的上下层之间实现全连接,而每层神经元之 ...

  10. CSS垂直居中对齐

    用CSS有多种方法实现垂直居中对齐.如果已知外部div的高度,不管是否知道内部div的高度,垂直居中实现起来很简单,但如果内部div高度是变量,如文字,垂直居中实现起来就比较复杂了,很可能需要使用ha ...