NYOJ 304 節能 -- 區間dp

/*
	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
*/

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