题目描述
某工厂收到了 n n n 个产品的订单,这 n n n 个产品分别在 A、B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工。
某个产品 i i i 在 A、B 两车间加工的时间分别为 A i , B i A_i,B_i Ai,Bi。怎样安排这 n n n 个产品的加工顺序,才能使总的加工时间最短。
这里所说的加工时间是指:从开始加工第一个产品到最后所有的产品都已在 A、B 两车间加工完毕的时间。
输入格式
第一行仅—个整数 n n n,表示产品的数量。
接下来一行 n n n 个整数是表示这 n n n 个产品在 A 车间加工各自所要的时间。
最后的 n n n 个整数是表示这 n n n 个产品在 B 车间加工各自所要的时间。
输出格式
第一行一个整数,表示最少的加工时间。
第二行是一种最小加工时间的加工顺序。
样例 #1
样例输入 #1
5
3 5 8 7 10
6 2 1 4 9
样例输出 #1
34
1 5 4 2 3
提示
1 ≤ n ≤ 1000 1\leq n\leq 1000 1≤n≤1000。
贪心 - AC
对于A,有一个顺序后,顺着加工就行了,没有任何阻碍。
对于B,我一开始疑惑,是否一定与A的顺序一致。显然是这样的,不一致一定不会带来好处。
题目里要输出的,也只是一个顺序而已。
图大概是这样的:
A可以连续来,B就不一样了,中间可能为了等待而断开来。
最终答案是由B决定的,而B过程中加工时间恒定,所以要使等待时间最小化。
来猜贪心结论。
想要塞B,就算一直等一直等也没有关系,但是A少一点。猜测先加工
a
i
≤
b
i
a_i\leq b_i
ai≤bi的,再加工
a
i
>
b
i
a_i>b_i
ai>bi的。
对于
a
i
≤
b
i
a_i\leq b_i
ai≤bi,猜测
a
i
a_i
ai从小到大排序。一来,最开始那个a肯定得加到等待时间。二来,b比a大,这样也许可以给后面留时间,允许a越来越大。三来,就算由于一开始b可能小,等待时间也是很小的一点一点累积的。
我不知道怎么表达清楚,但是感觉上,这样好像是对的。
对于
a
i
>
b
i
a_i>b_i
ai>bi,猜测
b
i
b_i
bi从大到小排序。快死了,多吃点好的吧。
这确实是正确的,交上去一遍过了。所以猜贪心结论很重要。
至于其正确性的证明,下面我想说几点……
struct Node {
ll a, b; int ind;
Node(ll _a, ll _b, int _ind): a(_a), b(_b), ind(_ind){}
};
int n;
ll a[MAXN], b[MAXN], ans;
vector<Node> u, v;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%lld", a + i);
}
for (int i = 1; i <= n; ++i) {
scanf("%lld", b + i);
}
for (int i = 1; i <= n; ++i) {
if (a[i] <= b[i]) u.push_back(Node(a[i], b[i], i));
else v.push_back(Node(a[i], b[i], i));
}
sort(u.begin(), u.end(), [](const Node& x, const Node& y) { return x.a < y.a; } );
sort(v.begin(), v.end(), [](const Node& x, const Node& y) { return x.b > y.b; } );
ll sa = 0;
for (Node i : u) {
sa += i.a;
if (ans >= sa) ans += i.b;
else ans = sa + i.b;
}
for (Node i : v) {
sa += i.a;
if (ans >= sa) ans += i.b;
else ans = sa + i.b;
}
printf("%lld\n", ans);
for (Node i : u) printf("%d ", i.ind);
for (Node i : v) printf("%d ", i.ind);
printf("\n");
return 0;
}