【區間dp】關路燈 牛客網題解

鏈接:https://ac.nowcoder.com/acm/contest/93/J?&headNav=www
來源:牛客網
注:我提交的時候,後臺判題程序有問題,java沒法AC,實際上代碼是沒問題的。

時間限制:C/C++ 2秒,其他語言4秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld

題目描述

我國現在能源消耗非常嚴重,現在政府有這樣一個工作,每天早上都需要把一些路燈關掉,
但是他們想讓在關閉的過程中所消耗的能源是最少的,負責路燈關閉的工作人員以1m/s的速度進行行走,
假設關閉路燈的時候不需要花費任何的時間,請你編寫一個程序,計算在給定路燈位置和每個路燈的消耗能源的多少,
求出當所有路燈關閉的時候所需要的最少能量

輸入描述:

多組測試數據循環輸入
每組測試數據第一行:N表示路燈的數量 (2<=N <=1000)
第二行:V表示開始關燈的路燈號碼。 (1<=V<=N)
接下來的N行中,每行包含兩個用空格隔開的整數D和W,用來描述每盞燈的參數
D表示該路燈到原點的距離 (用米爲單位來表示),
W表示燈泡的功率,即每秒該燈泡所消耗的能量數。(0<=D<=1000,0<=W<=1000)
路燈按照順序給出,起始位置的那盞燈不算消耗的電能裏面
輸出描述:
輸出一個整數,即消耗能量之和的最小值。

示例1
輸入

4
3
2 2
5 8
6 1
8 7

輸出

56
說明
對於樣例,我一開始在第三個路燈的位置,即在6位置
第1s的時候去5把第二盞燈關閉,消耗電能8
然後去第四盞燈,第四盞燈亮的時間是4s 所以消耗電能28
最後去關第一盞燈第一盞燈亮的時間是10s 所以消耗電能20
最後總和爲8+28+20=56

分析:
定義dp[i][j]。
將數組分爲三部分,最中間的是處理過的,那麼肯定右兩個指針分割它們,那麼,dp[i][j]的意義爲
已經處理過的部分[i,j],消耗的最小能源值是多少。
從圖上可以看出來,二維表dp[i][j]還需要保存工作人員當前的位置。
則設置dp[i][j][2],同樣可以看成二維dp表,即一個單元格存兩個數,這樣好理解。
工作人員每次去往下一個地方,就是i和j向左右擴展,並且工作人員當前要嘛在i處,要嗎在j處,即dp[i][j][0]表示在左邊,dp[i][j][1]表示在右邊。
在這裏插入圖片描述
每次去往下一個地方花的時間算出來,乘以[1,i-1]以及[i+1,N]上的功率總和。就是浪費的時間。
W[i]重新定義爲1到i上的功率總和。
用來加速求一個段上的總和,比如總和[1,i]就是W[i],總和[i+1,N],就是W[N]-W[i]
顯然,最開始的時候當前位置即可以看作在左邊,也可以看作在右邊,那麼的dp[V][V][0]=dp[V][V][1]=0
最終結束的位置是dp[1][N][0]和dp[1][N][1]。
畫表後得知,三個條件,畫三條紅線,i<=V,j>=V,且i<j,可知只需對右上角的小正方形做dp即可(其左底角位置爲[V][V])。
狀態依賴:
舉個例子:dp[i][j][0]表示中間處理好的一段爲i到j,現在工作人員在左邊,那麼它可能是工作人員在右邊走過來的,即由dp[i][j-1][1]轉移過來的,也可能是一直都在左邊,就是又往左走了一步,即由dp[i+1][j]轉移過來的。
其他情況分析後和這個都是一樣的。
狀態依賴爲dp[i][j]依賴dp[i+1][j]和dp[i][j-1]。可知每個單元格依賴它下面的和左邊的,即從下到上,從左往右dp即可。
其中的具體轉移看代碼dp主體,迴歸題意就能看懂,其中摳細節比較費時間。在這裏插入圖片描述
填寫初始dp
那麼,需要填寫base case,即第V行的前V個,和第V列的前V個
第V列 從下往上時,dp只依賴於它下面的,根據意義可知,它下面的單元格j是固定爲V的,迴歸到題意,說明一次也不能往右移動,每次都只能往左移動
所以dp[i][V][0]是如何求的,很容易理解
而dp[i][V][1]怎麼求呢,很簡單,dp[i][V][0]變爲dp[i][V][1],意思就是從這頭跑到那頭,不關任何燈。
上代碼:

import java.util.*;
/**
 * @author week
 * @Title: Turn_off_the_street_lights
 * @ProjectName algorithm
 * @Description: TODO
 * @date 2019/6/1216:04
 */
public class Turn_off_the_street_lights {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        while (sc.hasNext()){
            int N=sc.nextInt();
            int V=sc.nextInt();
            int D[]=new int[N+1];
            int W[]=new int[N+1];
            for(int i=1;i<=N;i++){
                D[i]=sc.nextInt();
                W[i]=sc.nextInt();
                W[i]+=W[i-1];
            }
            long dp[][][]=new long[N+1][N+1][2];
            for(int i=V-1;i>0;i--){
                dp[i][V][0]=dp[i+1][V][0]+(D[i+1]-D[i])*(W[i]+W[N]-W[V]);
                dp[i][V][1]=dp[i][V][0]+(D[V]-D[i])*(W[i-1]+W[N]-W[V]);
            }
            for(int i=V+1;i<=N;i++){
                dp[V][i][1]=dp[V][i-1][1]+(D[i]-D[i-1])*(W[V-1]+W[N]-W[i-1]);
                dp[V][i][0]=dp[V][i][1]+(D[i]-D[V])*(W[V-1]+W[N]-W[i]);
            }
            //寫不寫都行,dp[V][V][0]=dp[V][V][1]=0;
            for(int i=V-1;i>0;i--){
                for(int j=V+1;j<=N;j++){
                    dp[i][j][0]=Math.min(dp[i+1][j][1]+(D[j]-D[i])*(W[i]+W[N]-W[j]),dp[i+1][j][0]+(D[i+1]-D[i])*(W[i]+W[N]-W[j]));
                    dp[i][j][1]=Math.min(dp[i][j-1][0]+(D[j]-D[i])*(W[i-1]+W[N]-W[j-1]),dp[i][j-1][1]+(D[j]-D[j-1])*(W[i-1]+W[N]-W[j-1]));
                }
            }
            System.out.println(Math.min(dp[1][N][0],dp[1][N][1]));
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章