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