zjoi 2007 storage 仓库建设 动态规划

【问题描述】

       L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。


  工厂i目前已有成品数量Pi;
       由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。

       由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci。对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外销售处设置在山脚的工厂N,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的,假设一件产品运送1个单位距离的费用是1。假设建立的仓库容量都都是足够大的,可以容下所有的产品。

       你将得到以下数据:

   工厂i距离工厂1的距离Xi(其中X1=0);

  在工厂i建立仓库的费用Ci;  

请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。

思路:dp斜率优化

 1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<cmath>
5 using namespace std;
6 #define MAXN 1000101
7 struct queue
8 {
9 long long sum,g;
10 };
11 int n;
12 long long dp[MAXN],h[MAXN],sum[MAXN],s[MAXN],g[MAXN];
13 queue Q[MAXN];
14 long long d[MAXN],p[MAXN],c[MAXN];
15 void init()
16 {
17 p[0]=d[0]=c[0]=dp[0]=h[0]=sum[0]=g[0]=h[0]=0;
18 for(int i=1;i<=n;i++)
19 {
20 sum[i]=sum[i-1]+p[i];
21 s[i]=s[i-1]+d[i]*p[i];
22 h[i]=sum[i]*d[i]-s[i]+c[i];
23 }
24 Q[1].sum=0; Q[1].g=0;
25 }
26
27 int main()
28 {
29 freopen("storage.in","r",stdin);
30 freopen("storage.out","w",stdout);
31 long long INF=(1<<30);
32 INF*=(1<<30);
33 int i,j,left,right;
34 left=right=1;
35 long long t;
36 scanf("%d",&n);
37 for(i=1;i<=n;i++)
38 {
39 scanf("%d%d%d",d+i,p+i,c+i);
40 }
41 init();
42 for(i=1;i<=n;i++)
43 {
44 while(left<right&&(Q[left+1].sum-Q[left].sum)*d[i]>Q[left+1].g-Q[left].g)
45 left++;
46 dp[i]=Q[left].g-d[i]*Q[left].sum+h[i];
47 g[i]=dp[i]+s[i];
48 while(right>left&&(g[i]-Q[right].g)*(Q[right].sum-Q[right-1].sum)<=(Q[right].g-Q[right-1].g)*(sum[i]-Q[right].sum))
49 right--;
50 Q[++right].sum=sum[i]; Q[right].g=g[i];
51 }
52 printf("%lld\n",dp[n]);
53 return 0;
54 }



原文地址:https://www.cnblogs.com/myoi/p/2415724.html