生产汽车(单调队列+斜率优化)

本文介绍了一种解决汽车生产调度问题的算法,通过分析工人的工作效率和汽车的组装复杂度,利用斜率优化的方法来确定最优的生产计划,以实现最小化整体生产时间的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

生产一台汽车需要从1号工人开始,当1号完成他的工作后,2号就会开始工作,然后是3号,最后当N号工人完成他的工作后,整个汽车生产完毕。工人们一共需要生产M台汽车,而且必须按照从1到M的顺序去生产。

对于工人i,他完成自己的工作需要Ti的时间,而对于汽车j,组装复杂度为Fj。那么工人i花在汽车j上的时间为Ti*Fj。

当某个工人完成他的工作后,他会同时把汽车交给下一个工人,没有任何时间上的延迟,因此,要保证下一个要接受汽车的工人必须是空闲的。为了满足这个要求,ABC需要为每一台汽车选择一个好时机开始制造。

ABC想知道生产完所有汽车最少需要多少时间。

Solution
经过分析可发现:
设g[i]为i车最早生产时间。g[1]=0
g[i]=g[i1]+Maxni=1(sum[j]f[i1]sum[j1]f[i])
Gj=(sum[j]f[i1]sum[j1]f[i])
看着这相似的结构,考虑斜率优化。
假如有k , k>j , Gk>Gj也就是k决策点优于j
将G展开得到
fifi1<sumksumjsumk1sumj1
我们可以将每个决策视为二维平面上的点(sumk,sumk1)
假设有三个点a,b,c
T(a,b)=sumbsumasumb1suma1
若b是决策点当且仅当T(a,b)>const,T(b,c)<const=>T(a,b)>T(b,c)
这意味这我们要维护斜率单调减,维护出一个下凸壳,在凸壳上二分出决策点

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std ;

#define N 100010

typedef long long ll ;

ll n , m , t[N] , sum[N] , f[N] , g[N] , q[N] , i , j , k ;

ll cross( ll x , ll y , ll  a , ll b ) {
    return x * b - y * a ;
}

int main () { 
    scanf("%lld%lld",&n,&m ) ;
    for( i=1 ; i<=n ; i++ ) {
        scanf("%lld",&t[i] ) ;
        sum[i] = sum[i-1] + t[i] ;
    }
    for( i=1 ; i<=m ; i++ ) scanf("%lld",&f[i] ) ;
    int l = 1 , r = 0 ;
    for( i=1 ; i<=n ; i++ ) {
        while( l<=r-1 && cross( sum[i-1]-sum[ q[r-1]-1 ],sum[i]-sum[ q[r-1] ] , sum[ q[r]-1 ]-sum[ q[r-1]-1 ],sum[ q[r] ]-sum[ q[r-1] ] ) < 0 ) r-- ;
            q[++r] = i ;    
    }
    g[1] = 0 ;
    for( i=2 ; i<=m ; i++ ) {
        int L = l ,  R = r-1 ;
        double va = ( f[i] ) / double( f[i-1] ) ;
        while( L<=R ) {
            int M = ( L + R ) / 2 ; 
            if( ( sum[ q[M+1] ]-sum[ q[M] ] ) / double( sum[ q[M+1]-1 ]-sum[ q[M]-1 ] ) > va ) L = M + 1 ; else R = M - 1 ;
        }
        g[i] = g[i-1] + sum[ q[L] ] * f[i-1] - sum[ q[L]-1 ] * f[i] ;
    }
    printf("%lld\n", g[m] + sum[n] * f[m] ) ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值