时间限制: 1 s
空间限制: 128000 KB
题目等级 : 大师 Master
题目描述 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
数据范围及提示 Data Size & Hint
【题目大意】
把路灯都关了的最小花费。
【思路】
区间dp
从V开始关灯 所关 的灯一定是一段连续的,因为你经过了这个路灯不可能不关。
这一段连续的序列是从V点开始扩展的。
f[i][j][0]为i--j的灯都关了之后你是站在i位置的,f[i][j][1]为你站在j位置。
那么当你发生状态转移时,假设i--j你都关了,那么浪费的电能就是你走的时间*(总功率-你关了的(i--j)的功率和)前缀和就好啦。
【code】
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,p; int d[1001],w[1001],f[1001][1001][3]; int main() { scanf("%d%d",&n,&p); for(int i=1;i<=n;i++) { scanf("%d%d",&d[i],&w[i]); w[i]+=w[i-1]; } memset(f,127/3,sizeof(f)); f[p][p][0]=f[p][p][1]=0; for(int i=p;i>=1;i--) for(int j=i+1;j<=n;j++) { f[i][j][0]=min(f[i][j][0],f[i+1][j][0]+(d[i+1]-d[i])*(w[n]-(w[j]-w[i]))); f[i][j][0]=min(f[i][j][0],f[i+1][j][1]+(d[j]-d[i])*(w[n]-(w[j]-w[i]))); f[i][j][1]=min(f[i][j][1],f[i][j-1][0]+(d[j]-d[i])*(w[n]-(w[j-1]-w[i-1]))); f[i][j][1]=min(f[i][j][1],f[i][j-1][1]+(d[j]-d[j-1])*(w[n]-(w[j-1]-w[i-1]))); } printf("%d ",min(f[1][n][1],f[1][n][0])); return 0; }