您的位置:首页 > 其它

poj 1180:Batch Scheduling【斜率优化dp】

2018-05-26 11:55 447 查看

我会斜率优化了!这篇讲的超级棒https://blog.csdn.net/shiyongyang/article/details/78299894?readlog
首先列个n方递推,设sf是f的前缀和,st是t的前缀和:
\[ f[i]=min(f[j]+s*(sf
-sf[j])+st[i]*(sf[i]-sf[j])) \]
然后移项:
\[ f[i]=f[j]+s*sf
-s*sf[j]+st[i]*sf[i]-st[i]*sf[j] \]
\[ f[i]=f[j]+s*sf
+st[i]*sf[i]-s*sf[j]-st[i]*sf[j] \]
\[ f[i]=f[j]+s*sf
+st[i]*sf[i]-sf[j]*(s+st[i]) \]
\[ f[i]+sf[j]*(s+st[i])=f[j]+s*sf
+st[i]*sf[i] \]
然后看成斜率表达式b+kx=y,那么
\[ b=f[i],x=sf[j],k=(s+st[i]),y=f[j]+s*sf
+st[i]*sf[i] \]
那么对于每个i都看成一个点(sf[i],f[j]+s*sf
+st[i]*sf[i]),然后在队列里维护斜率单调递增的点(下凸壳),考虑对于当前的i的斜率k,需要在下凸壳上找一个j点使得f[i],也就是b(截距)最小。
显然要找最后一条比k斜率小的点的右端点
然后用斜率去卡队首即可,加点的时候用斜率判断是否是下凸壳,否则去队尾

#include<iostream>
#include<cstdio>
using namespace std;
const long long N=10005,inf=1e18;
long long n,s,st
,sf
,f
,q
,l,r;
long long read()
{
long long r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
double wk(int j,int k)
{
return (double)((double)f[j]-(double)f[k])/(double)((double)sf[j]-(double)sf[k]);
}
int main()
{
n=read(),s=read();
for(int i=1;i<=n;i++)
st[i]=st[i-1]+read(),sf[i]=sf[i-1]+read();
// for(int i=1;i<=n;i++)
// cerr<<st[i]<<" "<<sf[i]<<endl;
for(int i=1;i<=n;i++)
{//cerr<<wk(q[l+1],q[l])<<"   "<<s+st[i]<<endl;
while(l<r&&wk(q[l+1],q[l])<s+st[i])
l++;
f[i]=f[q[l]]+s*(sf
-sf[q[l]])+st[i]*(sf[i]-sf[q[l]]);//cerr<<q[l]<<" "<<f[i]<<endl;
// for(int j=l;j<=r;j++)
// cerr<<q[j]<<" ";
// cerr<<endl;
while(l<r&&wk(i,q[r])<wk(q[r],q[r-1]))
r--;
q[++r]=i;
}
printf("%lld\n",f
);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: