關路燈

題目:關路燈

網址:https://www.luogu.com.cn/problem/P1220ios

題目描述

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

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

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

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

輸入格式

第一行是兩個數字 n(表示路燈的總數)和 c(老張所處位置的路燈號);io

接下來 n 行,每行兩個數據,表示第 1 盞到第 n 盞路燈的位置和功率。數據保證路燈位置單調遞增stream

輸出格式

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

輸入輸出樣例
輸入
5 3
2 10
3 20
5 20
6 30
8 10
輸出
270
說明/提示

樣例解釋
此時關燈順序爲** 3 4 2 1 5 **。
數據範圍
1≤n≤50, 1≤c≤n。數據

明確一點:老張關的路燈號必定是連續的(也就是說,不會存在「三過路燈不顧」的狀況);證實顯然。移動

咱們來定義狀態:對於老張,咱們先肯定當前處於的路燈位置,記做dp[pos],這樣會有顯式的問題,由於dp[pos]是從哪一個狀態轉移獲得的,不知道!所以,咱們還須要肯定已經處理過的路燈的範圍[L, R],因而咱們能夠定義狀態:dp[L, R, pos];不過留意一點,pos指的是當前正關的路燈號,由此可得對於已操做完成的區間[L, R](包含當前位置),pos = L 或 R。

因此,pos這一維是冗餘的,取而代之的是用0/1來表示當前處於位置的左右(1表示在R + 1處,0表示在L - 1處);而所算的代價偏偏是剩餘燈泡的電功率乘以這次移動的時間。
有方程:
dp[i, j, 0] = min{dp[i + 1, j, 0] + (pos[i + 1] - pos[i]) * (sum{p[k] | 1 <= k <= i} + sum{p[k] | j + 1 <= k <= n}), dp[i + 1, j, 1] + (pos[j] - pos[i]) * (sum{p[k] | 1 <= k <= i} + sum{p[k] | j + 1 <= k <= n})}
dp[i, j, 1] = min{dp[i, j - 1, 1] + (pos[j] - pos[j - 1]) * (sum{p[k] | 1 <= k < i} + sum{p[k] | j <= k <= n}), dp[i, j - 1, 0] + (pos[j] - p[i]) * (sum{p[k] | 1 <= k < i} + sum{p[k] | j <= k <= n})};

階段爲區間長度,決策是它的兩個來源:原區間的左側及右側。
dp[c, c] = 0,其他正無窮。

代碼以下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn = 50 + 1;
int n, c, p[maxn], loc[maxn], sum_front[maxn] = {}, sum_back[maxn] = {};
int dp[maxn][maxn][2];
int main()
{
	scanf("%d %d", &n, &c);
	
	for(int i = 1; i <= n; ++ i)
	{
		scanf("%d %d", &loc[i], &p[i]);
	}
	for(int i = 1; i <= n; ++ i)
	{
		sum_front[i] = sum_front[i - 1] + p[i];
	}
	for(int i = n; i > 0; -- i)
	{
		sum_back[i] = sum_back[i + 1] + p[i];
	}
	memset(dp, 0x3f, sizeof(dp));
	dp[c][c][0] = dp[c][c][1] = 0;
	for(int k = 2; k <= n; ++ k)
	{
		int L, R;
		for(L = 1; L <= n - k + 1; ++ L)
		{
			R = L + k - 1;
			dp[L][R][0] = min(dp[L + 1][R][0] + (loc[L + 1] - loc[L]) * (sum_front[L] + sum_back[R + 1]), dp[L + 1][R][1] + (loc[R] - loc[L]) * (sum_front[L] + sum_back[R + 1]));
			dp[L][R][1] = min(dp[L][R - 1][0] + (loc[R] - loc[L]) * (sum_front[L - 1] + sum_back[R]), dp[L][R - 1][1] + (loc[R] - loc[R - 1]) * (sum_front[L - 1] + sum_back[R]));
		}
	}
	printf("%d\n", min(dp[1][n][0], dp[1][n][1]));
	return 0;
}
相關文章
相關標籤/搜索