/*
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
最新推荐文章于 2017-11-27 19:21:19 发布