题目描述 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;
}