[题解]CEOI 2004 锯木厂选址
【題目描述】
從山頂上到山底下沿著一條直線種植了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
-----------------------------------------------------------我是分界線----------------------------------------------------------------------
【題解】
裸的單調隊列優化DP。今天zyy腦子壞掉了,一直腦抽啊腦抽,一直調不過調不過,然后發現是方程推錯了= =|| 。各種糾結之后,仔細一看是符號弄錯了!!! 看來功力還是不夠啊。。
選擇兩個鋸木廠,那么整條河流就被分成了三段,花費計算如下:
f[i]=w[1]*(x[j]-x[1])+w[2]*(x[j]-x[2])+...+w[j]*(x[j]-x[j]) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //1~j
? ? ? +w[j+1]*(x[i]-x[j+1])+w[j+2]*(x[i]-x[j+2])+...+w[i]*(x[i]-x[i]) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//j+1~i
? ? ? +w[i+1]*(x[n+1]-x[i+1])+w[i+2]*(x[n+1]-x[i+2])+...+w[n]*(x[n+1]-x[n]) ? ? ? ? ? ? //i+1~n
化簡之后:f[i]=Delta+Sum[w[j]]*x[j]-Sum[w[j]]*x[i] ?
我們令X=Sum[w[j]] ,Y=Sum[w[j]]*x[j] 。 當i固定時,維護(X,Y)。
下面給出代碼:
View Code 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 #define MAXN 20020 5 #define INF 0x7fffffff 6 int w[MAXN],d[MAXN],x[MAXN]; 7 int q[MAXN],Front,Back; 8 int n; 9 int ans,Sum,Delta; 10 inline void Get_int(int &Ret) 11 { 12 char ch; 13 bool flag=false; 14 for(;ch=getchar(),ch<'0'||ch>'9';) 15 if(ch=='-') 16 flag=true; 17 for(Ret=ch-'0';ch=getchar(),ch>='0'&&ch<='9';Ret=Ret*10+ch-'0'); 18 flag&&(Ret=-Ret); 19 } 20 void Read() 21 { 22 Get_int(n); 23 int i; 24 for(i=1;i<=n;i++) 25 { 26 Get_int(w[i]),Get_int(d[i]); 27 x[i+1]=x[i]+d[i]; 28 Sum+=x[i]*w[i]; 29 w[i]+=w[i-1]; 30 } 31 } 32 inline double Get(int i,int j) 33 { 34 return (double)(w[i]*x[i]-w[j]*x[j])/(double)(w[i]-w[j]); 35 } 36 void Work() 37 { 38 ans=INF; 39 Front=0,Back=-1; 40 int i; 41 for(i=1;i<=n;i++) 42 { 43 while(Front<Back&&Get(q[Back],q[Back-1])>=Get(i,q[Back])) 44 Back--; 45 q[++Back]=i; 46 while(Front<Back&&Get(q[Front],q[Front+1])<=x[i]) 47 Front++; 48 Delta=w[i]*x[i]+x[n+1]*(w[n]-w[i])-Sum; 49 ans=min(ans,Delta+w[q[Front]]*x[q[Front]]-x[i]*w[q[Front]]); 50 } 51 printf("%d\n",ans); 52 } 53 int main() 54 { 55 Read(); 56 Work(); 57 return 0; 58 }?
至此,此題完美解決。
轉載于:https://www.cnblogs.com/CQBZOIer-zyy/archive/2013/03/18/2966739.html
總結
以上是生活随笔為你收集整理的[题解]CEOI 2004 锯木厂选址的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ecshop“发货查询”中加入收货人、收
- 下一篇: Buffer Cache Hit Rat