关路灯(区间DP)

描述

Dr.Kong设计的机器人卡多越来越聪明。最近市政公司交给卡多一项任务,每天早晨5:00开始,它负责关掉ZK大道右侧上所有的路灯。

卡多每到早晨5:00准会在ZK大道上某盏路灯的旁边,然后他开始关灯。每盏灯都有一定的功率,机器人卡多有着自觉的节能意识,它希望在关灯期间,ZK大道右侧上所有路灯的耗电量总数是最少的。

机器人卡多以1m/s的速度行走。假设关灯动作不需要花费额外的时间,因为当它通过某盏路灯时就顺手将灯关掉。

请你编写程序,计算在给定路灯设置,灯泡功率以及机器人卡多的起始位置的情况下,卡多关灯期间,ZK大道上所有灯耗费的最小能量。

输入
有多组测试数据,以EOF为输入结束的标志
每组测试数据第一行: N 表示ZK大道右侧路灯的数量 (2≤ N ≤ 1000) 
第二行: V 表示机器人卡多开始关灯的路灯号码。 (1≤V≤N)
接下来的N行中,每行包含两个用空格隔开的整数D和W,用来描述每盏灯的参数

D表示该路灯与ZK大道起点的距离 (用米为单位来表示),
W表示灯泡的功率,即每秒该灯泡所消耗的能量数。路灯是按顺序给定的。
( 0≤D≤1000, 0≤W≤1000 )
输出
输出一个整数,即消耗能量之和的最小值。注意结果小于200,000,000
样例输入
4 
3
2 2
5 8
6 1
8 7

样例输出

56



解题思路:这道题很明显是用区间dp,可是与以往的区间dp不同,因为对于区间[i,j],机器人所处的位置要么在i,要么在j(因为机器人要移动到某一点才能关闭灯泡,所以对于某一段区间来说,机器人最后肯定在两个端点上,否则将不能成立),那么既然要表示在左端点还是右端点,所以我们再开三维数组dp[i][j][0]表示停留在i点,dp[i][j][1]表示停留在j点,那么剩下的就是状态方程了,跟普通的区间dp一样,很容易写出来。。具体的看代码



#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>


#define LL long long int
#define min(a,b) (a<b?a:b)


int dp[1005][1005][2];
int dis[1005];
int cost[1005];


const int MAX = 200000005;


int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);


int n,p;
while (~scanf("%d", &n))
{
scanf("%d", &p);
scanf("%d %d", &dis[0], &cost[0]);
for (int i = 1; i < n; ++i)
{
scanf("%d %d", &dis[i], &cost[i]);
cost[i] += cost[i - 1];
}
for (int i = 0; i < n; ++i)
{
for (int j = i; j < n; ++j)
{
dp[i][j][0] = dp[i][j][1] = MAX;
}
}
--p;
dp[p][p][0] = dp[p][p][1] = 0;
for (int k = 1; k < n; ++k)
{
for (int i = (p - k) > 0 ? (p - k) : 0; i <= p; ++i)
{
int j = i + k;
if (j >= n)
break;
dp[i][j][0] = min( dp[i + 1][j][1] + (dis[j] - dis[i])*(cost[i] + cost[n - 1] - cost[j]), dp[i + 1][j][0] + (dis[i + 1] - dis[i])*(cost[i] + cost[n - 1] - cost[j]));
dp[i][j][1] = min( dp[i][j - 1][1] + (dis[j] - dis[j - 1])*(cost[i - 1] + cost[n - 1] - cost[j - 1]), dp[i][j - 1][0] + (dis[j] - dis[i])*(cost[i - 1] + cost[n - 1] - cost[j - 1]));
}
}
printf("%d\n", min(dp[0][n - 1][0], dp[0][n - 1][1]));
}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值