嘘~ 正在从服务器偷取页面 . . .

洛谷P1248 加工生产调度 题解


洛谷P1248 加工生产调度 题解

题目链接:P1248 加工生产调度

题意

某工厂收到了 $n$ 个产品的订单,这 $n$ 个产品分别在 A,B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工。

某个产品 $i$ 在 A、B 两车间加工的时间分别为 $A_i,B_i$。怎样安排这 $n$ 个产品的加工顺序,才能使总的加工时间最短。

这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A、B 两车间加工完毕的时间。

输入格式

第一行仅—个整数 $n$,表示产品的数量。

接下来一行 $n$ 个整数是表示这 $n$ 个产品在 A 车间加工各自所要的时间。

最后的 $n$ 个整数是表示这 $n$ 个产品在 B 车间加工各自所要的时间。

输出格式

第一行一个整数,表示最少的加工时间。

第二行是一种最小加工时间的加工顺序。

数据范围

$1\leq n\leq 10^5$

贪心的常见套路似乎就是找到两个存在极小差异的决策,分析哪个更优,以归纳法获得最优决策。

考虑只有两个元素 $(a_1,b_1),(a_2,b_2)$ 时,设 $(a_1,b_1)$ 先处理更优。

先处理 $1$ 再处理 $2$ 的花费,所需时间即为最后加工完 $2$ 所需的时间

先处理 $2$ 再处理 $1$ 的花费,所需时间即为最后加工完 $1$ 所需的时间

根据假设可知

移项得

可以发现不等式左右较大的项均被抵消掉了,则

即 $\min \{b_2, a_1\}<\min \{b_1,a_2\}$ 。这个东西是有传递性的,但是我们不能直接排序。

原因在于 C++ 标准库要求用于排序的运算符必须满足严格弱序。

什么是严格弱序呢?

对于一个比较运算符 $<$ ,记 $\not<$ 为不满足该运算符,若满足以下四个条件,则称该运算符是严格弱序的。

  • $x \not< x$ (非自反性)
  • 若 $x < y$ ,则 $y \not< x$ (非对称性)
  • 若 $x < y, ~y < z$ ,则 $x < z$ (传递性)
  • 若 $x \not< y,~y \not< x, ~y\not< z,~z\not< y$ ,则 $x \not< z, z \not< x$ (不可比性的传递性)

而我们刚刚的排序并不满足不可比性的传递性。

也就是说刚刚的排序有 (记 $a \downarrow b$ 为 $\min\{a,b\}$ )

因此我们需要找到一个具有「不可比性的传递性」的式子。

分析一下刚刚的排序条件,可以发现这个和 $a,b$ 的大小有关。

  1. $a_1 < b_1 \land a_2 < b_2$ 时,按 $a_1 < a_2$ 排序。
  2. $a_1 = b_1\land a_2 = b_2$ 时,排序结果无影响。
  3. $a_1 > b_1 \land a_2 > b_2$ 时,按 $b_1 > b_2$ 排序。

可以发现这三种情况对应了 $a_i - b_i < 0,~a_i - b_i = 0,~a_i - b_i > 0$

因此我们将每个元素,第一维按 $\mathrm{sgn}(a_i - b_i)$ 排序,第二维按对应的排序方式排序,即可得到答案。

等有时间再研究研究这个严格弱序的东西,咕咕咕。

时间复杂度 $\mathcal{O}(n \log n)$

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define sgn(x) (((x) > 0) - ((x) < 0))
#define N ((int)(1e5+15))

int n,c1,c2,a[N],b[N],d[N],o[N];
bool cmp(int x,int y)
{
    if(d[x] != d[y]) return d[x] < d[y];
    return (d[x] <= 0) ? (a[x] < a[y]) : (b[x] > b[y]);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i=1; i<=n; i++) cin >> a[i];
    for(int i=1; i<=n; i++) cin >> b[i];
    for(int i=1; i<=n && (o[i] = i); i++) d[i] = sgn(a[i] - b[i]);
    sort(o + 1, o + 1 + n, cmp);
    c1 = a[o[1]]; c2 = a[o[1]] + b[o[1]];
    for(int i=2; i<=n; i++)
    { c2 = max(c1 + a[o[i]], c2) + b[o[i]]; c1 += a[o[i]]; }
    cout << c2 << '\n';
    for(int i=1; i<=n; i++) cout << o[i] << " \n"[i==n];
    return 0;
}

参考文献

[1] 题解 P1248 【加工生产调度】 - 心爱 的博客 - 洛谷博客

[2] 浅谈邻项交换排序的应用以及需要注意的问题 - ouuan的博客


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录