1. 程式人生 > >洛谷 P1220 關路燈 (區間DP)

洛谷 P1220 關路燈 (區間DP)

題目描述

某一村莊在一條路線上安裝了n盞路燈,每盞燈的功率有大有小(即同一段時間內消耗的電量有多有少)。老張就住在這條路中間某一路燈旁,他有一項工作就是每天早上天亮時一盞一盞地關掉這些路燈。

為了給村裡節省電費,老張記錄下了每盞路燈的位置和功率,他每次關燈時也都是儘快地去關,但是老張不知道怎樣去關燈才能夠最節省電。他每天都是在天亮時首先關掉自己所處位置的路燈,然後可以向左也可以向右去關燈。開始他以為先算一下左邊路燈的總功率再算一下右邊路燈的總功率,然後選擇先關掉功率大的一邊,再回過頭來關掉另一邊的路燈,而事實並非如此,因為在關的過程中適當地調頭有可能會更省一些。

現在已知老張走的速度為1m/s,每個路燈的位置(是一個整數,即距路線起點的距離,單位:m)、功率(W),老張關燈所用的時間很短而可以忽略不計。

請你為老張編一程式來安排關燈的順序,使從老張開始關燈時刻算起所有燈消耗電最少(燈關掉後便不再消耗電了)。

輸入輸出格式

輸入格式:

檔案第一行是兩個數字n(0<n<50,表示路燈的總數)和c(1<=c<=n老張所處位置的路燈號);

接下來n行,每行兩個資料,表示第1盞到第n盞路燈的位置和功率。

輸出格式:

一個數據,即最少的功耗(單位:J,1J=1W·s)。

輸入輸出樣例

輸入樣例#1:
5 3
2 10
3 20
5 20
6 30
8 10
輸出樣例#1:
270  

說明

輸出解釋:

{此時關燈順序為3 4 2 1 5,不必輸出這個關燈順序}

 1 /*
 2 考慮 四種情況消耗功率的最小值
3 如果 i,j路燈關了 i-j之間一定也關了 不要問為什麼 4 如果關閉一個區間的燈,最後人一定在這個區間的左邊或右邊,關了左邊或右邊的燈去中間沒必要。 5 //f[i][j][0]表示關了[i,j]區間的燈最後人在i點的最優值,f[i][j][1]表示關了[i,j]區間的燈最後人在j點的最優值 6 */ 7 #include<iostream> 8 #include<cstdio> 9 #include<cstring> 10 using namespace std; 11 int d[100],w[100],s,n; 12 int f[100][100][3];
13 int main() 14 { 15 scanf("%d%d",&n,&s); 16 for(int i=1;i<=n;i++) 17 scanf("%d%d",&d[i],&w[i]),w[i]+=w[i-1]; 18 memset(f,127/3,sizeof(f)); 19 f[s][s][0]=f[s][s][1]=0; 20 for(int i=s;i>=1;i--) 21 for(int j=i+1;j<=n;j++) 22 { 23 f[i][j][0]=min(f[i+1][j][0]+(d[i+1]-d[i])*(w[n]-(w[j]-w[i])),f[i][j][0]); 24 f[i][j][0]=min(f[i+1][j][1]+(d[j]-d[i])*(w[n]-(w[j]-w[i])),f[i][j][0]); 25 f[i][j][1]=min(f[i][j-1][1]+(d[j]-d[j-1])*(w[n]-(w[j-1]-w[i-1])),f[i][j][1]); 26 f[i][j][1]=min(f[i][j-1][0]+(d[j]-d[i])*(w[n]-(w[j-1]-w[i-1])),f[i][j][1]); 27 } 28 printf("%d",min(f[1][n][1],f[1][n][0])); 29 }
贖回你的淚光