bsoj 2684 【CEOI2004】鋸木廠選址

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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章