P1248 加工生产调度 题解
Lacrymabre · · 个人记录
这里提供一篇纯退火的题解。
题意不多赘述,本题需要输出最短的加工时间和加工顺序,有
因为我五分钟之内没有头绪,所以考虑随机化算法。
考虑猴子排序,每次随机打乱整个序列,每次计算按照打乱后的序列计算加工时间,多次打乱,就有可能找到最优解。
如果每次用 STL 打乱整个数列复杂度过高,可以退而求次之,每次打乱两项,就是随机交换两项。
具体代码如下
void gswap(int x,int y){
swap(a[x],a[y]);
swap(b[x],b[y]);
swap(id[x],id[y]);
}
void random_swap(){
x=rnd(n),y=rnd(n);
gswap(x,y);
fcnew=count();
}
值得注意的是,退火算法还要随机地接受一些较劣解。因为可能最优解要通过这些较劣解得到。
完整代码如下:
int rnd(int x){
if(x==0) return 0;
return (rand())%x+1;
}
ll count(){
ll res=0,tline=0;
for(int i=1;i<=n;i++){
tline+=a[i];
res=max(res,tline)+b[i];
}
return res;
}
void gswap(int x,int y){
swap(a[x],a[y]);
swap(b[x],b[y]);
swap(id[x],id[y]);
}
void mnth(){
int x,y;
ll fcold,fcnew,da;
ll t;
double delta;
while((db)clock()/CLOCKS_PER_SEC<0.97){
t=clock();
fcold=count();
x=rnd(n),y=rnd(n);
gswap(x,y);
fcnew=count();
delta=fcnew-fcold;
ans=min(ans,min(fcold,fcnew));
if(delta<0||exp(-(delta)/t)>=rand()%32768) continue;
else gswap(x,y);
}
}