zoukankan      html  css  js  c++  java
  • 加工生产调度

    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;
    }
    
  • 相关阅读:
    CSUST 8.4 早训
    CSUST 8.5 早训
    hdu1542 Atlantis 线段树--扫描线求面积并
    hdu1540 Tunnel Warfare 线段树/树状数组
    hdu1535 Invitation Cards 最短路
    hdu1358 Period KMP
    SQL Server 向数据库中创建表并添加数据
    初次实践数据库--SQL Server2016
    hdu1301 Jungle Roads 最小生成树
    hdu1281 棋盘游戏 二分图最大匹配
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11754082.html
Copyright © 2011-2022 走看看