[題解] P2120 [ZJOI2007]倉庫建設 動態規劃 斜率優化
阿新 • • 發佈:2021-01-30
[題解] P2120 [ZJOI2007]倉庫建設
洛谷題目連結
首先考慮用動態規劃
表示從第個到第個位置 (第個位置修建倉庫) 的代價
表示從第個到第個位置的成品總和
表示到第個位置到到第個位置的距離
表示從個到第個位置所有成品運輸到第個位置的代價
可以列出轉移方程
其中表示從第個到第個位置所有成品運到倉庫的代價
程式碼如下
#include <cstdio> #include <algorithm> using namespace std; const int N=1e6+7; int n,x[N],p[N],c[N],sum[N],s[N],f[N]; int Q[N],l=1,r=1; int X(int x){return Q[x]==0?0:-sum[Q[x]];} int Y(int x){return Q[x]==0?0:f[Q[x]]+s[Q[x]+1];} int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d%d",&x[i],&p[i],&c[i]); for(int i=1;i<=n;i++)x[i]=x[n]-x[i],sum[i]=sum[i-1]+p[i],s[i]=s[i-1]+x[i]*p[i]; for(int i=1;i<=n;i++){ f[i]=1e9+7; for(int j=0;j<i;j++)f[i]=min(f[i],f[j]+s[i]-s[j]-(sum[i]-sum[j])*x[i]+c[i]); } printf("%d",f[n]); return 0; }
但是顯然這方法複雜度是無法通過此題
觀察轉移方程,可以發現可以使用斜率優化
移項得到
其中單調不增,可以用斜率優化解決
程式碼如下
#include <cstdio> #include <algorithm> #define int long long using namespace std; const int N=1e6+7; int n,x[N],p[N],c[N],sum[N],s[N],f[N]; int Q[N],l=1,r=1; int X(int x){return Q[x]==0?0:-sum[Q[x]];} int Y(int x){return Q[x]==0?0:f[Q[x]]-s[Q[x]];} signed main(){ scanf("%lld",&n); for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&x[i],&p[i],&c[i]); for(int i=1;i<=n;i++)x[i]=x[n]-x[i],sum[i]=sum[i-1]+p[i],s[i]=s[i-1]+x[i]*p[i]; for(int i=1;i<=n;i++){ while(l<r&&((X(l)-X(l+1))*x[i]<=(Y(l)-Y(l+1))))++l; int j=Q[l]; f[i]=f[j]+s[i]-s[j]-sum[i]*x[i]+sum[j]*x[i]+c[i],Q[++r]=i; while(l+1<r&&(Y(r-2)-Y(r-1))*(X(r-1)-X(r))<=(Y(r-1)-Y(r))*(X(r-2)-X(r-1)))Q[r-1]=Q[r],--r; } printf("%lld",f[n]); return 0; }