某一村莊在一條路線上安裝了 \(n\) 盞路燈,每盞燈的功率有大有小(即同一段時間內消耗的電量有多有少)。老張就住在這條路中間某一路燈旁,他有一項工做就是天天早上天亮時一盞一盞地關掉這些路燈。c++
爲了給村裏節省電費,老張記錄下了每盞路燈的位置和功率,他每次關燈時也都是儘快地去關,可是老張不知道怎樣去關燈纔可以最節省電。他天天都是在天亮時首先關掉本身所處位置的路燈,而後能夠向左也能夠向右去關燈。開始他覺得先算一下左邊路燈的總功率再算一下右邊路燈的總功率,而後選擇先關掉功率大的一邊,再回過頭來關掉另外一邊的路燈,而事實並不是如此,由於在關的過程當中適當地調頭有可能會更省一些。數組
如今已知老張走的速度爲 \(1m/s\),每一個路燈的位置(是一個整數,即距路線起點的距離,單位:\(m\))、功率(\(W\)),老張關燈所用的時間很短而能夠忽略不計。spa
請你爲老張編一程序來安排關燈的順序,使從老張開始關燈時刻算起全部燈消耗電最少(燈關掉後便再也不消耗電了)。code
第一行是兩個數字\(n\)(表示路燈的總數)和 \(c\)(老張所處位置的路燈號);ci
接下來 \(n\) 行,每行兩個數據,表示第 \(1\) 盞到第 \(n\) 盞路燈的位置和功率。數據保證路燈位置單調遞增。it
一個數據,即最少的功耗(單位:\(J\),\(1J=1W×s\))。
輸入輸出樣例class
5 3
2 10
3 20
5 20
6 30
8 10程序
270im
此時關燈順序爲 3 4 2 1 5。
數據範圍數據
\(1≤n≤50,1≤c≤n\)
這個題從題目的意思,應該挺容易就能看出來是一個區間\(dp\),由於題意就是一個大爺在一個「區間」裏關燈。因此就能夠根據區間長度來進行狀態轉移。首先想到若是大爺關燈從\(i\)到\(j\),固然這並不表明關燈順序,大爺關燈確定是走過的路上的燈都關了,由於這確定比走過不關再回來關要優。而在\(i\)到\(j\)這一段關了燈的區間裏,大爺有兩種位置狀況,一種是在\(i\),也就是左邊,另外一種就是右邊,因此咱們的dp數組就能夠根據這個來開,也就是\(dp[i][j][0]\)和\(dp[i][j][1]\)分別表示關了i,j之間的燈,而後在最左和最右兩種位置的狀況,而區間長度確定是從最短到最長,最短爲1,而後依次增長,因此每一次的\(dp[i][j]\)的狀態都是從上一個轉移下來的,也就是\(dp[i+1][j]\)和$dp[i][j-1],而後分別在左右端點兩種,依次進行狀態轉移。而能耗的增量能夠經過時間和區間裏能耗的前綴和來進行轉移,下邊我用一個轉移方程來進行一下具體說明:
首先是個轉移方程:
在這裏,\(pos\)表明位置(這裏的位置說的是下標,不是距離,可是pos數組存的是距離,用來計算時間)\(sum\)數組表明的是從\(i\)到\(j\)以外的能耗,\(sum\)須要一個預處理,下邊單獨說,這裏先介紹含義,方便理解。這個狀態轉移方程的意思也就是\(i\)到\(j\)區間內,大爺在左邊的時候,經過不一樣的上個狀態的位置來進行轉移,值得一提的是,由於此時大爺在左邊界,因此確定是由\(dp[i+1][j]\)轉移而來,假如是由\(dp[i][j-1]\)轉移來的話,應當在右側,這就是下一個狀態轉移方程。繼續看這個方程,從\(dp[i+1][j]\)轉移而來,因此也有兩種,左右邊界各一種,在左邊界時,他所需的時間就是\(pos[i+1] - pos[i]\),右邊界時就是\(pos[j]-pos[i]\),而花費的功率就是sum乘以時間,分別爲:\((pos[i+1] - pos[i])\times sum[i+1][j]\)和\((pos[j]-pos[i])\times sum[i+1][j]\),看到這裏可能有人會有疑惑,從\(i\)到\(j\)以外的能耗爲啥是\(i+1\)到\(j\)呢,如今咱們來講一下\(sum\)的得出:咱們先用\(val\)數組當作前綴和,區間\(i\)到\(j\)的能耗就是\(val[j]-val[i-1]\),\(sum[i][j]\)就是用\(val[n]\)減去上邊的能耗,具體見代碼。如今大概就都解釋清楚了。而後就是兩個關鍵的狀態轉移方程:
就這樣了,而後看一下代碼加深一下理解⑧
#include<bits/stdc++.h> using namespace std; const int maxn = 55; int pos[maxn]; int sum[maxn][maxn]; int dp[maxn][maxn][3]; int v[maxn]; int n,c; int main(){ cin>>n>>c; for(int i=1;i<=n;++i){ int w; cin>>pos[i]>>w; v[i]=v[i-1]+w; } memset(dp,0x3f,sizeof(dp)); dp[c][c][0] = dp[c][c][1] = 0; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ sum[i][j] = v[n] - (v[j] - v[i-1]); } } for(int j = c;j<=n;++j){ for(int i=j-1;i>=1;--i){ dp[i][j][0] = min(dp[i+1][j][0]+(pos[i+1] - pos[i])*sum[i+1][j],dp[i+1][j][1]+(pos[j]-pos[i])*sum[i+1][j]); dp[i][j][1] = min(dp[i][j-1][1]+(pos[j]-pos[j-1])*sum[i][j-1],dp[i][j-1][0]+(pos[j]-pos[i])*sum[i][j-1]); } } int ans = min(dp[1][n][0],dp[1][n][1]); cout<<ans<<endl; }