poj 1180 IOI202 经典DP任务安排
朴素方程:f[i,j]=min{f[k,j-1]+(tx[i]-tx[j])*(t[i]+j*s)} ①
非常经典和常用的优化就是根据每一次启动和分段对后面产生影响,可以优化为:
f[i]=min{f[k]+(t[i]-t[j]+s)*(tx[i]-tx[k])+s*(tx[n]-tx[i])} ②
而更进一步可以写成更方便的一个方程:
f[i]=min{f[k]+(tx[n]-tx[k])*(s+t[i]-t[k])} ③
这个似乎更能充分的应用对后面的影响这一特点。
根据③这个方程,我们可以进行更强大的优化:斜率优化。
为了更方便的解释这一优化,我们另tx[i]=∑tx[i~n],∴tx[n]-tx[i]=新的tx[i+1];
假设j<k<i,而且j优于k,那么:
f[j]+(t[i]-t[j]+s)*tx[j+1]<f[k]+(t[i]-t[k]+s)*tx[k+1];
化简:
f[j]+t[i]*tx[j+1]-t[j]*tx[j+1]+s*tx[j+1]<f[k]+t[i]*tx[k+1]-t[k]*tx[k+1]+s*tx[k+1];
移项:
f[j]-f[k]-t[j]*tx[j+1]+s*tx[j+1]+t[k]*tx[k+1]-s*tx[k+1]<t[i]*tx[k+1]-t[i]*tx[j+1];
进一步:
(f[j]-f[k]-t[j]*tx[j+1]+s*tx[j+1]+t[k]*tx[k+1]-s*tx[k+1])/(t[i]*tx[k+1]-t[i]*tx[j+1])>t[i];
∴ 可以进行优化
不妨自己写出代码:
var
f,q,t,x,st,tx:array[0..10001]of int64;
s,k:int64;
n,head,tail,i:longint;
function ki(j,k:longint):double;
var
x:double;
begin
x:=(f[j]-f[k]+(tx[j+1]-tx[k+1])*s+tx[k+1]*st[k]-tx[j+1]*st[j])/(tx[k+1]-tx[j+1]);
exit(x);
end;
begin
readln(n);
readln(s);
for i:=1 to n do
begin
readln(t[i],x[i]);
st[i]:=st[i-1]+t[i];
end;
tx[n+1]:=0;
for i:=n downto 1 do
tx[i]:=tx[i+1]+x[i];
f[0]:=0; q[1]:=0; head:=1; tail:=1;
for i:=1 to n do
begin
while (head<tail)and(ki(q[head],q[head+1])<=st[i])do inc(head);
k:=q[head];
f[i]:=f[k]+tx[k+1]*(s+st[i]-st[k]);
while (head<tail)and(ki(q[tail-1],q[tail])>=ki(q[tail],i))do dec(tail);
inc(tail);
q[tail]:=i;
end;
writeln(f[n]);
end.
(此代码poj上未通过,不过自己和别的程序对拍了n组极限数据都能过)
浙公网安备 33010602011771号