加工生产调度

#如何高效记录并整理编程学习笔记?#

题目描述

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

某个产品 ii 在 A、B 两车间加工的时间分别为 A_i,B_iAi​,Bi​。怎样安排这 nn 个产品的加工顺序,才能使总的加工时间最短。

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

输入格式

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

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

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

输出格式

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

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

输入输出样例

输入 #1复制

5
3 5 8 7 10
6 2 1 4 9

输出 #1复制

34
1 5 4 2 3

说明/提示

1\leq n\leq 10001≤n≤1000。

感觉之前的题解都太复杂了……

读完题后,我们可以发现,这道题中的决策无后效性,可以用贪心来解。

如何确定贪心的顺序

首先,我们假设只有22个产品,在AA车间加工的时间为a1,a2a1,a2,在BB车间加工的时间为b1,b2b1,b2。我们假设先加工产品11的方案较优

如果先加工11,再加工22,所需时间即为最后加工完22所需的时间。也就是 a1+\max(b1,a2)+b2a1+max(b1,a2)+b2。

反过来,如果先加工22,再加工11,所需时间为 a2+max(b2,a1)+b1a2+max(b2,a1)+b1。

因为我们假设了先加工产品11的方案较优,所以前一种方案的时间更少,也就是 a1+\max(b1,a2)+b2 < a2+\max(b2,a1)+b1a1+max(b1,a2)+b2<a2+max(b2,a1)+b1 。

移项,得到 \max(b1,a2)-a2-b1 < \max(b2,a1)-b2-a1max(b1,a2)−a2−b1<max(b2,a1)−b2−a1

然后我们发现不等式两边较大的数都被消掉了,原式即为 -\min(b1,a2)<-\min(b2,a1)−min(b1,a2)<−min(b2,a1)

也就是\min(a1,b2)<\min(a2,b1)min(a1,b2)<min(a2,b1)

可以用贪心思想排序的题都有这么一条性质:如果22个物品按某种方法排序时结果较优,那么多个物品按这种方法排序时结果一定最优。

式子化不化简对于结果没有影响,下面是用a1+\max(b1,a2)+b2 < a2+\max(b2,a1)+b1a1+max(b1,a2)+b2<a2+max(b2,a1)+b1 排序的代码(洛谷上能A,但是方法是错的)

struct node{
	long long a,b;  //在两个车间分别加工的时间
	int in; //原来的下标
	bool operator<(const node &x)const{
		return a+max(b,x.a)+x.b < x.a+max(x.b,a)+b;//重载小于运算符,用于sort
	}
}c[1005];

sort(c+1,c+n+1);

为什么刚才的方法是错的

因为\sout{\min(a1,b2)<\min(a2,b1)}min(a1,b2)<min(a2,b1)​中,不等关系不具有传递性。

表示我翻了一下网上的题解发现都是这么说的,不过后来我手动模拟分类讨论逐一判断了一下发现这个式子具有传递性。

不等式的传递性是指:有3个元素x,y,zx,y,z和不等关系(此处设为a<ba<b),当x<yx<y且y<zy<z时,x<zx<z一定成立。

那么,基于上面的公式排序后,所有相邻的元素都满足\min(a1,b2)<\min(a2,b1)min(a1,b2)<min(a2,b1)时,最终结果是正确的。

下面我们考虑\min(a1,b2)=\min(a2,b1)min(a1,b2)=min(a2,b1)的情况。设有3个工件x,y,zx,y,z,我们发现当\min(x.a, y.b) = \min(x.b, y.a)min(x.a,y.b)=min(x.b,y.a)且\min(y.a, z.b) = \min(y.b, z.a)min(y.a,z.b)=min(y.b,z.a)时,\min(x.a, z.b) = \min(x.b, z.a)min(x.a,z.b)=min(x.b,z.a)不一定成立。

举个栗子:x.a = 3, x.b = 5, y.a = 1, y.b = 1, z.a = 6, z.b = 4x.a=3,x.b=5,y.a=1,y.b=1,z.a=6,z.b=4

如果有3个元素x,y,zx,y,z和不等关系(此处设为a<ba<b),当x<y, y<xx<y,y<x与y<z, z<yy<z,z<y均不成立时,x<zx<z与z<xz<x一定不成立,这叫做不可比性的传递性。

(你可以暂时理解为有三个数均相等,这是不可比性的传递性的一个例子。)

而在排序时的不等关系除了要满足传递性外,还要满足不可比性的传递性。所以不能够直接用\min(a1,b2)<\min(a2,b1)min(a1,b2)<min(a2,b1)排序。

(如果你对于上述说明还不能完全理解,可以参考一下dalao ouuan的文章 浅谈邻项交换排序的应用以及需要注意的问题 %%%ouuan tql)


所以我们要找出一个具有不可比性的传递性的式子

分析一下这个式子,我们发现这与两个元素a,ba,b的大小有关 :

  1. a1<b1a1<b1且a2<b2a2<b2时,按a1<a2a1<a2排序。

  2. a1=b1a1=b1且a2=b2a2=b2时,如何排序对结果没有影响。

  3. a1>b1a1>b1且a2>b2a2>b2时,按b2<b1b2<b1排序。

然后我们发现上面的不等式要优先找a比b小的,所以将上面的3种情况按顺序排即可。

于是我们设d_i=\begin{cases}-1&a_i<b_1\\0&a_i=b_i\\1&a_i>b_i\end{cases}di​=⎩⎪⎪⎨⎪⎪⎧​−101​ai​<b1​ai​=bi​ai​>bi​​

(也就是a_i-b_iai​−bi​的符号)

以d为第一关键字,d相等的按上面的规则排序即可。

这有个名词叫做Johnson 法则

排序代码 :

	bool operator<(const node &x)const{
		if(d==x.d){
			if(d<=0)return a<x.a;//这里的等于是将上面的情况2找了一种方法排序
			else return b>x.b;
		}
		return d<x.d;
	}

然后,这道题需要我们求出总共需要的时间。按题意模拟一下即可。

	fa=c[1].a;fb=c[1].a+c[1].b;//fa为i在车间A加工完需要的时间,fb为i在车间B加工完需要的时间
	for(int i=2;i<=n;++i){
		fb=max(fa+c[i].a,fb)+c[i].b;//i开始在车间B加工时,需要先在车间A加工完成,而且i-1需要完成在车间B的工序
        fa+=c[i].a;
	}

上代码:

#include<bits/stdc++.h>
using namespace std;
struct number
{
	int num,ind;
	bool sign;
	bool operator<(const number& ano)const
	{
		return num<ano.num;
	}
}p[2001];
int a[1001],b[1001],s[1001];
bool vis[1001];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		p[i].num=a[i];
		p[i].ind=i;
		p[i].sign=true;
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		p[i+n].num=b[i];
		p[i+n].ind=i;
		p[i+n].sign=false;
	}
	sort(p+1,p+2*n+1);
	int l=1,r=n;
	for(int i=1;i<=2*n;i++)
	{
		if(vis[p[i].ind])
			continue;
		vis[p[i].ind]=true;
		if(p[i].sign)
			s[l++]=p[i].ind;
		else
			s[r--]=p[i].ind;
		if(l>r)
			break;
	}
	int ta=0,tb=0;
	for(int i=1;i<=n;i++)
	{
		ta+=a[s[i]];
		tb=max(tb,ta);
		tb+=b[s[i]];
	}
	printf("%d\n",tb);
	for(int i=1;i<=n;i++)
		printf("%d ",s[i]);
	putchar('\n');
	return 0;
}

 

  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值