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
Sample Output
又是一道斜率優化。。
下面是演算過程:
令
令
對於 第一個鋸木廠選址
對於 第二個鋸木廠選址
則
總的費用爲
令
設
假設
#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;
}