现在的位置: 首页 > 综合 > 正文

poj 1180 IOI202 经典DP任务安排

2013年06月02日 ⁄ 综合 ⁄ 共 1353字 ⁄ 字号 评论关闭

朴素方程: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组极限数据都能过)

抱歉!评论已关闭.