Luogu P1248 加工生产调度 题解报告
【题目大意】
有$n$个任务要在两个流水线上完成,第$i$个任务在第一个流水线上需要$a_i$的时间完成,在第二个流水线上需要$b_i$的时间完成。每个任务要现在第一个流水线上完成之后才可以到第二个流水线上开始工作,求如何安排可以使得总时间最短。
【思路分析】
这个题目直接看好像有点复杂?我们先来想一下另一个简单一点的题目。
现在有$n$个小怪兽要打,你初始血量为$m$,打第$i$个小怪兽要消耗$a_i$点血,打死这个小怪兽后可以加$b_i$点血,求如何安排打小怪兽的顺序可以使得需要的初始血量$m$最少?
你需要保证在打小怪兽的过程中任意时刻血量大于0,所以首先可以想到一个很显然的贪心策略:
如果$b_i>a_i$,那么我肯定先打这个小怪兽,因为它总体是给我加血的。然后对于同样可以加血的小怪兽,我们把$a$小的排在前面显然是更优的。因为先少扣一点血,后面加了血之后血多了再多扣一点,这样可以使得需要的初始血量更少。
如果$b_i\le a_i$,那么我肯定后打这个小怪兽,因为它总体是给我扣血的,我前面加了一些血之后再扣血,需要的初始血量小一些,所以这样更优。然后我们可以把$a,b$换过来考虑,即把$a$看作$b$,把$b$看作$a$,那么就是上面提到的这种情况,我们把$b$从小到大排序(倒序是从小到大,正序就是从大到小)是最优的。
然后我们现在回到原来这道题。可以这么理解:
我完成一个任务要先浪费$a_i$的时间,然后可以补回$b_i$的时间,最后的答案=$\sum_{i=1}^{n}b_i$+浪费掉的总时间。为了保证在完成任务的过程中每个任务都是先在第一个流水线上完成后再到第二个流水线上去,我们需要预留一些时间用来被浪费掉(emmmm这句话看起来有点蠢?QAQ),也就是要保证任意时刻都有时间可以浪费(相当于上面说道的血量大于0,即还有血可以被扣),那么显然可以参照上面的思路来做。
【代码实现】
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define g() getchar() 7 #define rg register 8 #define go(i,a,b) for(rg int i=a;i<=b;i++) 9 #define back(i,a,b) for(rg int i=a;i>=b;i--) 10 #define db double 11 #define ll long long 12 #define il inline 13 #define pf printf 14 using namespace std; 15 int fr(){ 16 int w=0,q=1; 17 char ch=g(); 18 while(ch<'0'||ch>'9'){ 19 if(ch=='-') q=-1; 20 ch=g(); 21 } 22 while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g(); 23 return w*q; 24 } 25 const int N=1002; 26 int n,ans,num1,num2,a[N],b[N],sum; 27 struct wk{ 28 int a,b,id; 29 }w1[N],w2[N]; 30 il bool cmp(wk x,wk y){return x.a<y.a;} 31 il bool cmq(wk x,wk y){return x.b>y.b;} 32 int main(){ 33 //freopen("","r",stdin); 34 //freopen("","w",stdout); 35 n=fr(); 36 go(i,1,n) a[i]=fr(); 37 go(i,1,n) b[i]=fr(),sum+=b[i]; 38 go(i,1,n){ 39 if(a[i]<b[i]) w1[++num1]=(wk){a[i],b[i],i}; 40 else w2[++num2]=(wk){a[i],b[i],i}; 41 } 42 sort(w1+1,w1+1+num1,cmp);sort(w2+1,w2+1+num2,cmq); 43 rg int as=0;//记录整个过程中时间的变化 44 go(i,1,num1){ 45 as-=w1[i].a; 46 ans=max(ans,-as);//ans记录预备用来浪费的时间 47 as+=w1[i].b; 48 } 49 go(i,1,num2){ 50 as-=w2[i].a; 51 ans=max(ans,-as); 52 as+=w2[i].b; 53 } 54 pf("%d\n",ans+sum); 55 go(i,1,num1) pf("%d ",w1[i].id); 56 go(i,1,num2) pf("%d ",w2[i].id); 57 puts(""); 58 return 0; 59 }