/*
http://acm.nyist.net/JudgeOnline/problem.php?pid=304 節能
一個區間裏面有很多不重複的燈,機器人從其中一個燈開始關燈。
給出燈和原點的距離 和 燈的功率,問機器人從開始關燈到關燈結束總共浪費的電能
機器人每秒移動一米。
因爲各個燈消耗的電能不一樣,所以機器人的關燈的選擇有一定策略
思路 區間dp
dp[i][j][0] [i,j]之間的燈關閉了,機器人在第i個燈,浪費的最小電能
dp[i][j][1] [i,j]之間的燈關閉了,機器人在第j個燈,浪費的最小電能
顯然想要計算當前區間[i,j]之間的最小電能,可以由 區間[i+1,j]或 區間[i,j-1]推算
對於這兩個區間,可以從任意一個區間的左端點或者右端點到達當前區間
dp[i,j][0] = min(dp[i+1,j][0] + [i+1,j]區間外浪費的電能, dp[i+1,j][1] + [i+1,j]區間外浪費的電能);
dp[i,j][1] = min(dp[i,j-1][0] + [i,j-1]區間外浪費的電能, dp[i,j-1][1] + [i,j-1]區間外浪費的電能);
另外:由前綴和[0,i],[0,j]求任意區間和[i,j]的時候 [i,j] = [j,0] - [i-1,0]
*/
#pragma comment(linker, "/stack:64000000")
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define CLR(c,v) memset(c,v,sizeof(c))
template <typename _T>
_T Abs(_T a ){
return (a>0)?(a):(-a);
}
template <typename _T>
_T Max(_T a , _T b){
return (a>b)?(a):(b);
}
template <typename _T>
_T Max(_T a , _T b, _T c){
return (a>Max(b,c))?(a):(Max(b,c));
}
template <typename _T>
_T Min(_T a , _T b){
return (a<b)?(a):(b);
}
template <typename _T>
_T Min(_T a , _T b, _T c){
return (a<Min(b,c))?(a):(Min(b,c));
}
const int inf = -(1<<30);
const int INF = (1<<30);
const double eps = 1e-8;
const int M = 1e3 +10;
int d[M]; // 前綴和 路燈位置
int dp[M][M][2]; // dp[i][j][0] [i,j]區間 karl機器人在左端點 的最小消耗 dp[i][j][1] 爲在右端點
int c[M]; // 前綴和 每個路燈的消耗 每秒多少w
int main()
{
freopen("in.txt","r",stdin);
int n;
while( cin >> n ){
int s; cin >> s;
int sumW = 0; // 所有路燈每秒總消耗
//CLR(dp,0);CLR(c,0);CLR(d,0);
d[0] = c[0] = 0;
dp[s][s][0] = dp[s][s][1] = 0;
for(int i = 1 ; i <= n ; i++){
scanf("%d %d",&d[i],&c[i]); // d已經是前綴和了
sumW += c[i];
c[i] += c[i-1]; // 前綴和
}
for(int i = s-1 ; i >= 1 ; i--){ // 初始化前半
dp[i][s][0] = dp[i+1][s][0] + (d[i+1] - d[i])*(sumW - c[s] + c[i+1-1]);
dp[i][s][1] = dp[ i ][s][0] + (d[ s ] - d[i])*(sumW - c[s] + c[ i -1]);
}
for(int j = s+1 ; j <= n ; j++){ // 初始化後半
dp[s][j][1] = dp[s][j-1][1] + (d[j] - d[j-1])*(sumW - c[j-1] + c[s-1]);
dp[s][j][0] = dp[s][ j ][1] + (d[j] - d[ s ])*(sumW - c[ j ] + c[s-1]);
}
for(int i = s-1 ; i >= 1 ; i--){ // 中間到左邊
for(int j = s+1 ; j <= n ; j++) {// 中間到右邊
dp[i][j][0] = Min(
dp[i+1][j][0] + (d[i+1] - d[i])*(sumW - c[j] + c[i+1-1]) ,
dp[i+1][j][1] + (d[ j ] - d[i])*(sumW - c[j] + c[i+1-1]) );
dp[i][j][1] = Min(
dp[i][j-1][0] + (d[j] - d[ i ])*(sumW - c[j-1] + c[i-1]) , // 這裏減去的是已經關閉的燈消耗的電能。
dp[i][j-1][1] + (d[j] - d[j-1])*(sumW - c[j-1] + c[i-1]) );
}
}
int ans = Min(dp[1][n][0] , dp[1][n][1]);
printf("%d\n" , ans);
}
return 0;
}
/*
5
3
0 5
2 1
3 2
6 10
10 4
=158
*/
NYOJ 304 節能 -- 區間dp
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.