1. 程式人生 > >「LuoguP1220」 關路燈(區間dp

「LuoguP1220」 關路燈(區間dp

-s 輸出格式 article sin 最小值 區間 都是 algorithm 單位

題目描述

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

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

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

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

輸入輸出格式

輸入格式:

文件第一行是兩個數字n(1<=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,不必輸出這個關燈順序}


題解

吐槽:這是一道會生崽的題所以肥腸重要QAQ(大概也就考過個三四次改編題了吧

就是比較基礎的區間dp啦

設F[L][R][0]為區間[L,R]的燈都關掉,並且站在區間左端時已經消耗的功率最小值,

同理,F[L][R][1]為區間[L,R]的燈都關掉,並且站在區間右端是已消耗功率的最小值。

轉移方程:

f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*(sum[n]+(sum[i]-sum[j])),
                    f[i
+1][j][1]+(a[j]-a[i])*(sum[n]+(sum[i]-sum[j]))); f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*(sum[n]+(sum[i-1]-sum[j-1])), f[i][j-1][1]+(a[j]-a[j-1])*(sum[n]+(sum[i-1]-sum[j-1])));

最後的答案是F[1][n][0]和F[1][n][1]中的較小值。

 1 /*
 2     qwerta
 3     P1220 關路燈
 4     Accepted
 5     100
 6     代碼 C++,0.87KB
 7     提交時間 2018-07-04 17:04:07
 8     耗時/內存
 9     0ms, 2195KB
10 */
11 #include<cmath>
12 #include<cstdio>
13 #include<cstring>
14 #include<iostream>
15 #include<algorithm>
16 using namespace std;
17 int a[57];
18 int n,c;
19 int sum[57];
20 void scan()
21 {
22     scanf("%d%d",&n,&c);
23     int u;
24     for(int i=1;i<=n;++i)
25     {
26         scanf("%d%d",&a[i],&u);
27         sum[i]=sum[i-1]+u;
28     }
29     return;
30 }
31 int f[57][57][2];
32 void run()
33 {
34     memset(f,127,sizeof(f));
35     f[c][c][0]=f[c][c][1]=0;
36     for(int l=1;l<n;++l)
37     for(int i=1;i+l<=n;++i)
38     {
39         int j=i+l;
40         f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*(sum[n]+(sum[i]-sum[j])),
41                        f[i+1][j][1]+(a[j]-a[i])*(sum[n]+(sum[i]-sum[j])));
42         f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*(sum[n]+(sum[i-1]-sum[j-1])),
43                        f[i][j-1][1]+(a[j]-a[j-1])*(sum[n]+(sum[i-1]-sum[j-1])));
44     }
45     return;
46 }
47 int main()
48 {
49     scan();
50     run();
51     cout<<min(f[1][n][0],f[1][n][1]);
52     return 0;
53     //我當年的碼風真醜
54 }

「LuoguP1220」 關路燈(區間dp