P1248 加工生产调度

link

Solution:

贪心神仙题。

tips: 对于贪心题目,先考虑两个东西时的情况,一般是可以扩展到多个东西的情况的

此时我们考虑两订单 \(i\)\(j\)

  • \(i\)\(j\) : \(a[i]+\max(b[i],a[j])+b[j]\)

  • \(j\)\(i\) : \(a[j]+\max(b[j],a[i])+b[i]\)

此时我们按这个东西来做 \(\rm cmp\) 就会发现它不对。

为什么呢?

因为这个东西它不具有传递性

如果仔细想想,就会发现按这个排序,对于排完序后下标递增的三个数 \(i,j,k\),他可能不是最优解。说白了,就是这个东西是局部最优解,它不能拓展为全局最优解

(然鹅这个时候我就不会了)

那么我们感性理解一下,越少时间的工序对后面的影响越小。于是我们在两个数组未被安排过的里面找最小值。

找到的最小值可能在 \(a\) 也有可能在 \(b\) ,分讨一下:

1.若最小值是 \(a_i\) ,则此时对于任何一个未被安排的工序 \(j\) ,一定有 \(a_i\le a_j,b_i,b_j\) 。对于上式化简,显然的,应该将 \(i\) 工序安排在 \(j\) 工序前。

2.若最小值是 \(b_i\) ,同理可得,对于任何一个未被安排过得工序 \(j\) 要将 \(j\) 工序安排在 \(i\) 工序前。

那么做法也就一目了然了:

  • 先找到 \(a\)\(b\) 中没有安排过工序中的时间最小值。

  • 若最小值在 \(a\) 数组中,则将此工序安排在未安排工序的首部。

  • 若最小值在 \(b\) 数组中,则将此工序安排在未安排工序的尾部。

  • 求完顺序后模拟一次得到答案

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N=3e4+10;
int order[N],lo,ro;// order 是安排顺序,lo、ro是左端点和右端点
int n,a[N],b[N];
struct node{
	int c,id;// id 为原数组中的编号,c=min(a[i],b[i])
	bool lft;// 是放在首部还是尾部
}rk[N];
bool cmp(struct node n1,struct node n2){
	return n1.c<n2.c;
}

signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	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;i++){
		rk[i].id=i;rk[i].c=min(a[i],b[i]);
		if(rk[i].c==a[i])rk[i].lft=true;// a[i] 小则放在首部
		else rk[i].lft=false;// 否则就是尾部
	}
	sort(rk+1,rk+n+1,cmp);
	lo=1,ro=n;
	for(int i=1;i<=n;i++){
		if(rk[i].lft)order[lo++]=rk[i].id;
		else order[ro--]=rk[i].id;
	}
	int ta=0,tb=0;// A 厂和 B 厂的最后一工序结束时间
 	for(int i=1;i<=n;i++){
		int x=order[i];
		ta+=a[x];tb=max(ta,tb)+b[x];// 直接模拟
	}
	cout<<max(ta,tb)<<endl;
	for(int i=1;i<=n;i++)cout<<order[i]<<" ";
	
	return 0;
}
posted @ 2024-04-25 13:13  Little_corn  阅读(9)  评论(0编辑  收藏  举报