动态规划(斜率优化):[CEOI2004]锯木厂选址

锯木场选址(CEOI2004)

从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。

木材只能按照一个方向运输:朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小。假定运输每公斤木材每米需要一分钱。

任务

你的任务是写一个程序:

从标准输入读入树的个数和他们的重量与位置

计算最小运输费用

将计算结果输出到标准输出

输入

输入的第一行为一个正整数n——树的个数(2≤n≤20 000)。树从山顶到山脚按照1,2……n标号。接下来n行,每行有两个正整数(用空格分开)。第i+1行含有:wi——第i棵树的重量(公斤为单位)和 di——第i棵树和第i+1棵树之间的距离,1≤wi ≤10 000,0≤di≤10 000。最后一个数dn,表示第n棵树到山脚的锯木厂的距离。保证所有树运到山脚的锯木厂所需要的费用小于2000 000 000分。

输出

输出只有一行一个数:最小的运输费用。

样例

输入

9

1 2

2 1

3 3

1 1

3 2

1 6

2 1

1 2

1 1

输出

26

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int maxn=20010;
 6 long long W[maxn],F[maxn],D[maxn],X[maxn];    
 7 long long ans=2147483647;
 8 int q[maxn],st,ed;
 9 int main(){
10 #ifndef ONLINE_JUDGE
11     freopen("two.in","r",stdin);
12     freopen("two.out","w",stdout);
13 #endif
14     int n;
15     scanf("%d",&n);
16     for(int i=1;i<=n;i++){
17         scanf("%lld%lld",&W[i],&D[i+1]);
18         W[i]+=W[i-1];D[i+1]+=D[i];
19         X[i]=X[i-1]+(D[i]-D[i-1])*W[i-1];
20     }
21     n+=1;
22     X[n]=X[n-1]+(D[n]-D[n-1])*W[n-1];
23     q[st]=1;
24     for(int i=2;i<n;i++){
25         while(st<ed){
26             if(W[q[st+1]]*D[q[st+1]]-W[q[st]]*D[q[st]]<=
27                 D[i]*(W[q[st+1]]-W[q[st]]))
28                 st++;
29             else break;    
30         }
31         ans=min(ans,X[n]+W[q[st]]*(D[q[st]]-D[i])+W[i]*(D[i]-D[n]));
32         while(st<ed){
33             if((W[i]*D[i]-W[q[ed]]*D[q[ed]])*(W[q[ed]]-W[q[ed-1]])<=
34                 (W[q[ed]]*D[q[ed]]-W[q[ed-1]]*D[q[ed-1]])*(W[i]-W[q[ed]]))
35                 ed--;
36             else break;    
37         }
38         q[++ed]=i;
39     }
40     printf("%lld
",ans);
41     return 0;    
42 }
尽最大的努力,做最好的自己!
原文地址:https://www.cnblogs.com/TenderRun/p/5553346.html