【动态规划11】vijos1243生产产品(dp+单调队列)

题目描述

在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行。由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同。机器i完成第j个步骤的时间为T[i,j]。把半成品从一台机器上搬到另一台机器上也需要一定的时间K。同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤。也就是说,如果有一台机器连续完成了产品的L个步骤,下一个步骤就必须换一台机器来完成。现在,dd_engi的OI商店有史以来的第一个产品就要开始生产了,那么最短需要多长时间呢?
某日Azuki.7对跃动说:这样的题目太简单,我们把题目的范围改一改
对于菜鸟跃动来说,这是个很困难的问题,他希望你能帮他解决这个问题

输入输出格式

第一行有四个整数M, N, K, L 下面的N行,每行有M个整数。
第I+1行的第J个整数为T[J,I]。
输出只有一行,表示需要的最短时间。

设f[i][j]为生产前i个产品且第i个产品在j机器上生产的最小代价。
那么很容易想到的动态转移方程是f[i][j]=min(f[k][p]+sum[k+1][i][j])其中p!=j且k < <script type="math/tex" id="MathJax-Element-81"><</script>i。
sum[i][j][k]表示从第i件到第j件都在k机器上完成的单价和,然而显然可以用前缀和优化,式子再变成
f[i][j]=min(f[k][p]+sum[i][j]-sum[k][j])。这显然是难以维护的。
但是我们发现题目中j的个数很少,那么对于每一个确定的j(假如j==1)的时候,sum[i][j]显然是一个定值,f[i][1]=min(f[k][p]-sum[k][1])+sum[i][1],那么我们需要做的是维护从i-l+1到i区间内f[k][p]-sum[k][1]的最小值。
那么显然可以用单调队列优化。
话说vijos的评测机真是他妈诡异..

#include<bits/stdc++.h>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
const int maxn=100010;
const int INF=1e9+7;
using namespace std;
/*----------------------------------------------------------------------------*/
inline int read()
{
    char ls;int x=0,sng=1;
    for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
    for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
    return x*sng;
}
/*----------------------------------------------------------------------------*/
int m,n,cost,l;
int T[6][maxn],f[maxn][6],q[6][maxn][2],h[6],t[6],ans=INF;
int main()
{
    scanf("%d%d%d%d",&m,&n,&cost,&l);
    fer(i,1,n)
        fer(j,1,m){scanf("%d",&T[i][j]);T[i][j]+=T[i][j-1];}
    fer(i,1,m)
        fer(j,1,n)
            f[i][j]=INF;
    fer(i,1,n)q[i][t[i]][0]=0;
    fer(i,1,m)
    {
        fer(k,1,n)
        {
            while(h[k]<=t[k]&&i-q[k][h[k]][0]>l)h[k]++;
            int pos=q[k][h[k]][0],s=q[k][h[k]][1];
            f[i][k]=min(f[pos][s]-T[k][pos]+T[k][i]+cost,f[i][k]);
        }
        fer(k,1,n)
            fer(j,1,n)
                if(k!=j)
                {
                    while(h[j]<=t[j]&&f[i][k]-T[j][i]<=f[q[j][t[j]][0]][q[j][t[j]][1]]-T[j][q[j][t[j]][0]])t[j]--;
                    q[j][++t[j]][0]=i,q[j][t[j]][1]=k;
                }
    }
    fer(i,1,n)
    ans=min(ans,f[m][i]);
    cout<<ans-cost;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值