问题描述
某工厂有 件物品需要进行加工,并且每件物品都需要先在 工厂加工 分钟,然后在 工厂加工 分钟,, 工厂每次分别只能加工一件物品,问你最少需要多少时间能够加工完全部 件物品
交换论证
假设有 件待完成事件,当前完成了 件,所花时间为 ,设当前先完成 事件再完成 事件的总时间代价为 ,先完成 事件再完成 事件的总时间代价为 ,那么若能够找到关于 的满足条件,那么该条件即为贪心法则的完备条件
Johnson 法则
- 令 ,
- 将 中作业依照 增序排列, 中作业依 减序排列
- 中作业接 中作业构成满足 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; }