codevs 1258 关路灯

题目描述 Description

多瑞卡得到了一份有趣而高薪的工作。每天早晨他必须关掉他所在村庄的街灯。所有的街灯都被设置在一条直路的同一侧。

多瑞卡每晚到早晨5点钟都在晚会上,然后他开始关灯。开始时,他站在某一盏路灯的旁边。

每盏灯都有一个给定功率的电灯泡,因为多端卡有着自觉的节能意识,他希望在耗能总数最少的情况下将所有的灯关掉。

多端卡因为太累了,所以只能以1m/s的速度行走。关灯不需要花费额外的时间,因为当他通过时就能将灯关掉。

编写程序,计算在给定路灯设置,灯泡功率以及多端卡的起始位置的情况下关掉所有的灯需耗费的最小能量。

输入描述 Input Description

输入文件的第一行包含一个整数N,2≤N≤1000,表示该村庄路灯的数量。

第二行包含一个整数V,1≤V≤N,表示多瑞卡开始关灯的路灯号码。

接下来的N行中,每行包含两个用空格隔开的整数D和W,用来描述每盏灯的参数,其中0≤D≤1000,0≤W≤1000。D表示该路灯与村庄开始处的距离(用米为单位来表示),W表示灯泡的功率,即在每秒种该灯泡所消耗的能量数。路灯是按顺序给定的。

输出描述 Output Description

输出文件的第一行即唯一的一行应包含一个整数,即消耗能量之和的最小值。注意结果小超过1,000,000,000。

样例输入 Sample Input

4

3

2 2

5 8

6 1

8 7

样例输出 Sample Output

56

题解

区间dp。考虑多瑞卡不可能走过一个灯不关,所以在任意阶段,街上已关的等为连续的一段,且多瑞卡必定站在该段的左或右端。所以考虑f[i][j][0/1]表示第i号灯到第j号灯段已关,多瑞卡站在该段的左(0)右(1)端上时,所要花费的最小代价。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define inf 90000000000000LL
using namespace std;
int n,m;
long long f[1002][1002][2],sum[1002],tot;
struct deng{int d,w;} a[1002];
void init()
{
	scanf("%d%d",&n,&m);
	int i;
	for(i=1;i<=n;i++)
	   {scanf("%d%d",&a[i].d,&a[i].w);
	    sum[i]=sum[i-1]+a[i].w;
	   }
	tot=sum[n];
}
void dp()
{
	int i,j,k;
	for(i=1;i<=n;i++)
	for(j=1;j<=n;j++)
	   f[i][j][0]=f[i][j][1]=inf;
	f[m][m][0]=f[m][m][1]=0; 
	for(j=1;j<n;j++)
	   {for(i=1;i+j<=n;i++)
	       {k=i+j;
			f[i][k][0]=min(f[i][k][0],f[i+1][k][0]+(tot-sum[k]+sum[i])*(a[i+1].d-a[i].d));
			f[i][k][0]=min(f[i][k][0],f[i+1][k][1]+(tot-sum[k]+sum[i])*(a[k].d-a[i].d));
			f[i][k][1]=min(f[i][k][1],f[i][k-1][1]+(tot-sum[k-1]+sum[i-1])*(a[k].d-a[k-1].d));
			f[i][k][1]=min(f[i][k][1],f[i][k-1][0]+(tot-sum[k-1]+sum[i-1])*(a[k].d-a[i].d));
		   }
	   }
	printf("%lld\n",min(f[1][n][0],f[1][n][1]));
	
}
int main()
{
	init(); dp();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值