问题描述

某工厂有 件物品需要进行加工,并且每件物品都需要先在 工厂加工 分钟,然后在 工厂加工 分钟, 工厂每次分别只能加工一件物品,问你最少需要多少时间能够加工完全部 件物品

交换论证

假设有 件待完成事件,当前完成了 件,所花时间为 ,设当前先完成 事件再完成 事件的总时间代价为 ,先完成 事件再完成 事件的总时间代价为 ,那么若能够找到关于 的满足条件,那么该条件即为贪心法则的完备条件

Johnson 法则

  1. ,
  2. 中作业依照 增序排列, 中作业依 减序排列
  3. 中作业接 中作业构成满足 Johnson 法则的最优调度

基于交换论证的 Johnson 法则证明

假设当前已完成了 件物品的加工,其序列如下:


定义为工厂 加工完前 件物品所花时间, 为工厂 加工完成前 件物品所花时间,那么此时有

根据交换论证的步骤,接下来需要讨论加工顺序为 所花时间的大小关系

设此时先加工第 件物品所花时间为 ,先加工第 件物品所花时间为 ,则有:


将上式中的 移入 内部,得:


显然当 为最大值时对答案没有影响,故将其剔除


不妨设 ,则有:

即当物品 和物品 满足 条件时,

但是该条件是不完备的,即该条件不满足传递性,若此时 ,则理论上,事实上也确实如此,但是由于 ,所以 的前缀和 对于后续答案的统计是有影响的,出现这种情况的根源在于推导式子时正确的传递条件应当在 的条件下继续判断 的大小,以满足排序条件的传递性

下面这组例子可以帮助理解:

3
2 100 3
1 1 1

这三件物品根据判断条件来看是等价的,但是其加工顺序不一样会导致结果不一样

再举一个例子,假设此时 ,理论上来说总时间 并且有 ,但若此时 为无穷大,则会导致 工厂流水线阻塞,为了避免这种情况或者说为了使得对于 ,我们显然需要将 小的先行加工

那么问题究竟出在了哪里呢?

在上述推导中显然我们只考虑了两件物品的先后关系,若每两件物品均满足 的优先关系,称任意两件物品具有可比性,若 ,则需要考虑其顺序的后效性,或者说是排序条件的传递性

AC Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
struct Node {
    ll a, b, id;
} p[maxn];
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) p[i].id = i;
    for (int i = 1; i <= n; ++i) cin >> p[i].a;
    for (int i = 1; i <= n; ++i) cin >> p[i].b;
    sort(p + 1, p + n + 1, [&](Node x, Node y) {
        if (min(x.b, y.a) == min(y.b, x.a)) return x.a < y.a;
        return min(x.b, y.a) > min(y.b, x.a);
        });
    ll x = 0, y = 0;
    for (int i = 1; i <= n; ++i) {
        x += p[i].a;
        y = max(x, y) + p[i].b;
    }
    cout << y << '\n';
    for (int i = 1; i < n; ++i) cout << p[i].id << " ";
    cout << p[n].id << '\n';
    return 0;
}