加工生产调度

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\n",t);
    printf("%d",x[1].id);
    for(int i=2;i<=n;i++)
        printf(" %d",x[i].id);
    return 0;
}
posted @ 2019-10-28 18:10  fbz  阅读(290)  评论(0编辑  收藏  举报