bsoj 2684 【CEOI2004】锯木厂选址

来源:互联网 发布:坚持 知乎 编辑:程序博客网 时间:2024/05/16 13:54

Description
  从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。
  木材只能按照一个方向运输:朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小。假定运输每公斤木材每米需要一分钱。
  你的任务是编写一个程序,从输入文件中读入树的个数和他们的重量与位置,计算最小运输费用。
Input
  输入的第一行为一个正整数n——树的个数(2≤n≤20000)。树从山顶到山脚按照1,2……n标号。接下来n行,每行有两个正整数(用空格分开)。第i+1行含有:wi——第i棵树的重量(公斤为单位)和 di——第i棵树和第i+1棵树之间的距离,1≤wi≤10000,0≤di≤10000。最后一个数dn,表示第n棵树到山脚的锯木厂的距离。保证所有树运到山脚的锯木厂所需要的费用小于2000000000分。
Output
  输出只有一行一个数:最小的运输费用。
Sample Input
9
12
21
33
11
32
16
21
12
11
Sample Output
26

又是一道斜率优化。。
下面是演算过程:

S[i]表示前i棵树的总重量

Sd[i]表示前i棵树的总距离

d[i]表示ii+1的距离

对于 第一个锯木厂选址
Cost[i]=Cost[i1]+S[i1]d[i1]

对于 第二个锯木厂选址
W[i][j]=Cost[j]Cost[i1]S[i1](Sd[j]Sd[i1])

总的费用为
F[i]=min(Cost[j]+W[j+1][i]+W[i+1][n+1])

G[j]=Cost[j]+W[j+1][i]+W[i+1][n+1]
=Cost[n+1]S[j](Sd[i]Sd[j])S[i](Sd[n+1]Sd[i])

j<k<i

假设G[j]>G[k](k比j优)

Cost[n+1]S[j](Sd[i]Sd[j])S[i](Sd[n+1]Sd[i])>Cost[n+1]S[k](Sd[i]Sd[k])S[i](Sd[n+1]Sd[i])

S[j]Sd[j]S[k]Sd[k]>S[k]Sd[i]+S[j]Sd[i]

S[j]Sd[j]S[k]Sd[k]>Sd[i](S[j]S[k])

S[k]>S[j]

(S[j]Sd[j]S[k]Sd[k])/(S[j]S[k])<Sd[i]

#include<iostream>#include<iomanip>#include<cstring>#include<cmath>#include<cstdio>using namespace std;int d[20005],Sd[20005],S[20005];int Cost[20005];int Ans=0x7fffffff;int q[20005];double Slpoe(int j,int k){    return (S[j]*Sd[j]-S[k]*Sd[k])*1.0/(S[j]-S[k]);}int main(){    int n;    scanf("%d",&n);    int x;    for(int i=1;i<=n;i++){        scanf("%d%d",&x,&d[i]);        S[i]=S[i-1]+x;        Sd[i]=Sd[i-1]+d[i-1];        Cost[i]=Cost[i-1]+S[i-1]*d[i-1];    }    S[n+1]=S[n];    Sd[n+1]=Sd[n]+d[n];    Cost[n+1]=Cost[n]+S[n]*d[n];    int l=1;    int r=1;    q[1]=0;    for(int i=1;i<=n;i++){        while(l<r&&Slpoe(q[l],q[l+1])<Sd[i])l++;        int j=q[l];        Ans=min(Ans,Cost[n+1]-S[j]*(Sd[i]-Sd[j])-S[i]*(Sd[n+1]-Sd[i]));        while(l<r&&Slpoe(q[r-1],q[r])>Slpoe(q[r],i))r--;        q[++r]=i;    }    printf("%d",Ans);    return 0;}
1 0
原创粉丝点击