加工生产调度

https://loj.ac/problem/10003

题目描述

  有n个产品需要先后进行A、B两个任务,求最小的任务完成时间及任意一种加工顺序。

思路

  从直观上看,可以知道最优调度一定要使第一个机器不要有空闲,第二个机器的空闲时间尽可能短。这道题是Johnson法则的模板:先行工序施工工期短要排在前,后续工序施工工期短要放在后面。在这道题中,我们只需将所有任务分为两个集合,(N_1={A任务时间大于等于B任务时间})(N_2={A任务时间小于B任务时间}),将(N_1)中的任务按(A)任务时间升序排序,将(N_2)中的任务按(B)任务时间降序排序,依次遍历(N_1)(N_2)中的任务,得到的便是最优解。下面就需要证明这个贪心策略的正确性。

  证明:

  假设序列(S={J_1,J_2,...,J_n}),为加工部件的作业顺序,我们设t为经过t时刻B机器可以开始加工A机器中已经完成加工的产品。

  再设完成任务的最短时间(T(S,t)=min{a_i + T(S - {J_i},b_i + max(t - a_i,0))}),关于(T)这个等式显然是成立的,因为(min)中完成任务的时间为(T)(除去(i)产品的序列,(B)机器还需要的总时间)+完成第(i)个产品(A)任务的时间。

  我们运用反证法,假设任务i在任务j之前执行:

  (T(S,t)=a_i+T(S - {J_i},b_i + max{t - a_i,0}))

       (=a_i+a_j+T(S-{J_i + J_j},b_j + max{b_i + max{t-a_i} - a_j,0}))
//(max{t’ - a_j,0})中的(t’=b_i + max{t - a_i,0} - a_j)即做i产品时还需时间减做j产品A任务时间

       (=a_i+a_j+T(S-{J_i + J_j},T_{ij}))

  (T_{ij} = b_j + max{b_i + max{ t - a_i } - a_j,0})

    (= b_j + b_i - a_j + max{t - a_i ,a_j - b_i , 0 })

    (= b_j + b_i - a_j - a_i + max{t ,a_j + a_i - b_i , a_i })

  那么如果将产品i和产品j的工作顺序调换,那么可以得到

  (T’(S,t)= a_i + a_j + T(S - {J_i,J_j},T_{ji}))

  (T_{ji}=b_i + b_j - a_i - a_j + max{t,a_i + a_j - b_j,a_j})

  由于假设了(i)产品在(j)产品之前生产为最优方案,那么有(T ≤ T’)

  所以:(max{t ,a_j + a_i - b_i , a_i } ≤ max{t ,a_i + a_j - b_j,a_j})

  (由于一种不知名的原因可以消去(t),此处留坑)

  因此:(a_i + a_j +max{ -b_i , -a_j} ≤ a_i + a_j +max{ -b_j , -a_i})

  即(max{ b_i , a_j } ≥ max{ b_j , a_i }) 也就是(Johnson)法则的公式

  (color{red}{但这里不能用这个条件作为sort的cmp,因为它并不满足传递性})

代码

#include <bits/stdc++.h>
using namespace std;
struct machine
{
    int a,b,id;
}x[1100],x1[1100],x2[1100];
bool cmp1(machine a,machine b)
{
    return a.a<=b.a;
}
bool cmp2(machine a,machine b)
{
    return a.b>=b.b;
}
int main() 
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x[i].a);
        x[i].id=i;
    }
    for(int i=1;i<=n;i++)
        scanf("%d",&x[i].b);
    int cnt1=0,cnt2=0;
    for(int i=1;i<=n;i++)
        if(x[i].a<x[i].b)x1[++cnt1]=x[i];
        else x2[++cnt2]=x[i];
    sort(x1+1,x1+cnt1+1,cmp1);
    sort(x2+1,x2+cnt2+1,cmp2);
    int ans=0,t=0,k=0;
    for(int i=1;i<=n;i++)
        if(i<=cnt1)x[i]=x1[i];
        else x[i]=x2[i-cnt1];
    for(int i=1;i<=n;i++)
    {
        k+=x[i].a;
        if(t<k)t=k;
        t+=x[i].b;
    }
    printf("%d
",t);
    printf("%d",x[1].id);
    for(int i=2;i<=n;i++)
        printf(" %d",x[i].id);
    return 0;
}
原文地址:https://www.cnblogs.com/fangbozhen/p/11754082.html