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;
}
标签:node,工序,struct,加工,P1248,安排,调度,int,最小值
From: https://www.cnblogs.com/little-corn/p/18157456