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组极限数据都能过)

你可能感兴趣的:(poj)