Luogu P1248 加工生产调度

题目描述

某工厂收到了 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 1n1000

贪心 - AC

对于A,有一个顺序后,顺着加工就行了,没有任何阻碍。
对于B,我一开始疑惑,是否一定与A的顺序一致。显然是这样的,不一致一定不会带来好处。
题目里要输出的,也只是一个顺序而已。

图大概是这样的:
在这里插入图片描述
A可以连续来,B就不一样了,中间可能为了等待而断开来。
最终答案是由B决定的,而B过程中加工时间恒定,所以要使等待时间最小化。

来猜贪心结论。
想要塞B,就算一直等一直等也没有关系,但是A少一点。猜测先加工 a i ≤ b i a_i\leq b_i aibi的,再加工 a i > b i a_i>b_i ai>bi的。
对于 a i ≤ b i a_i\leq b_i aibi,猜测 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值