poj1180

斜率优化dp

据说这题朴素的O(n2)dp也可以A 没试过

朴素的dp不难想:f[i]=min(f[j]+sumtime[i]*sumcost[j+1,i]+c*sumcost[j+1,n]) 稍微解释一下,当选择j+1~i为同一批任务的时候

               j+1~n的任务都要额外花费开机的时间

复杂度是O(n2),有没有更好的方法呢?

我们用t[i]表示前i个任务的总时间,w[i]表示前i个任务的总费用;

方程式即为f[i]=min(f[j]+t[i]*(w[i]-w[j])+c*(w[n]-w[j]));

对于当前阶段i,考虑两个决策j,k, 假定k>j

当决策k优于决策j时,即f[k]+t[i]*(w[i]-w[k])+c*(w[n]-w[k])<=f[j]+t[i]*(w[i]-w[j])+c*(w[n]-w[j])

将常数都放在一边,整理可得

(t[i]+c)(w[k]-w[j])/(f[k]-f[j])>=1

显然f是单调增的,对于两个决策k,j,只要满足这个条件,k就一定优于j

我们考虑将左边设为决策G(k,j);

对于k<j<i

当G(i,j)>G(j,k) j一定不是最优

1 当G(i,j)>=1 时 显然i比j优

2 当G(i,j)<1 时 则G(j,k)<1则 k比j优

所以j可以被舍去

这样我们可以通过单调队列来维护 复杂度O(n)

 1 var f,t,w:array[0..10010] of int64;
 2     q:array[0..10010] of longint;
 3     h,c,i,j,n,r:longint;
 4 function top(k,j:longint):int64;
 5   begin
 6     exit(w[k]-w[j]);
 7   end;
 8 
 9 function down(k,j:longint):int64;   
10   begin
11     exit(f[k]-f[j]);
12   end;
13 
14 begin
15   readln(n);
16   readln(c);
17   for i:=1 to n do
18     readln(t[i],w[i]);
19   for i:=1 to n do
20   begin
21     t[i]:=t[i]+t[i-1];
22     w[i]:=w[i]+w[i-1];
23   end;
24   h:=0;
25   r:=0;
26   f[0]:=0;
27   for i:=1 to n do
28   begin
29     while (h<r) and ((t[i]+c)*top(q[h+1],q[h])>=down(q[h+1],q[h])) do inc(h); //这里最好写成除法表示
30     j:=q[h];
31     f[i]:=f[j]+t[i]*(w[i]-w[j])+c*(w[n]-w[j]);
32     while (h<r) and (top(i,q[r])*down(q[r],q[r-1])>=top(q[r],q[r-1])*down(i,q[r])) do dec(r);
33     inc(r);
34     q[r]:=i;
35   end;
36   writeln(f[n]);
37 end.
View Code
原文地址:https://www.cnblogs.com/phile/p/4473268.html