Description
某一村庄在一条路线上安装了n盏路灯,每盏灯的功率(单位时间的耗电量)有大有小。老张就住在这条路中间某 一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯。为了给村里节省电费,老张记录下了每盏 路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电。他每天都是在 天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯。开始他以为,先算一下左边路灯的总功率 ,再算一下右边路灯的总功率,然后选择先关掉功率大的一边,再回过头来关掉另一边的路灯,这样可以最省电。 而事实并非如此,因为在关的过程中适当地调头有可能会更省一些。现在已知老张走的速度为1米/秒;每个路灯的 位置(是一个整数,即距路线起点的距离,单位:米);以及功率(W),老张关灯所用的时间很短而可以忽略不 计。请你为老张编一程序来安排关灯的顺序,使从老张开始关灯时刻算起所有灯消耗电最少(灯关掉后便不再消耗 电了)。
Format
Input
第1行是两个数字n和c,分别表示路灯数和老张所处位置的路灯号;
第2行至第n+1行,每行有两个整数。
其中第k+1行的第一个整数表示第k盏灯离路线起点的距离,第二个整数表示第k盏灯的功率。
以上n+1行中,每行的两个整数之间都有一个空格分隔。
1≤n≤1000,求得的最小耗电量不大于1×10^8
Output
只有一行,该行只有一个整数,表示求得的最少耗电量。(单位:J,1J=1W·秒)。
Samples
输入数据 1
5 3
2 10
3 20
5 20
6 30
8 10
Copy
输出数据 1
270
Copy
Hint 此时关灯顺序为34215,不必输出这个关灯顺序 有5盏灯,老张从第3盏灯开始关灯,最小耗电量 =1*30+4*20+5*10+11*10=270
思路
首先,我们发现,这道题像P1063 [NOIP2006 提高组] 能量项链和【Zju1602 】乘法游戏一样,都可以用合并Dp。
然后,再想怎么做,不难发现,我们可以用一个数组:
f[左边界][右边界][位置]
来储存时间。
再用前缀和:
for(int i=1;i<=n;i++){
cin>>z[i]>>x[i];
ld[i]=ld[i-1]+x[i];
}
储存没用数据。
然后,不难分析出关键代码:
f[m][m][1]=0;
f[m][m][0]=0;
for(int i=2;i<=n;i++){
for(int j=1;j<=n;j++){
long long zs=i+j-1;
f[j][zs][0]=min(f[j+1][zs][0]+(z[j+1]-z[j])*(ld[j]+ld[n]-ld[zs]),f[j+1][zs][1]+(z[zs]-z[j])*(ld[j]+ld[n]-ld[zs]));
f[j][zs][1]=min(f[j][zs-1][0]+(z[zs]-z[j])*(ld[j-1]+ld[n]-ld[zs-1]),f[j][zs-1][1]+(z[zs]-z[zs-1])*(ld[j-1]+ld[n]-ld[zs-1]));
}
}
而其中最关键的,只有三行:
long long zs=i+j-1;
f[j][zs][0]=min(f[j+1][zs][0]+(z[j+1]-z[j])*(ld[j]+ld[n]-ld[zs]),f[j+1][zs][1]+(z[zs]-z[j])*(ld[j]+ld[n]-ld[zs]));
f[j][zs][1]=min(f[j][zs-1][0]+(z[zs]-z[j])*(ld[j-1]+ld[n]-ld[zs-1]),f[j][zs-1][1]+(z[zs]-z[zs-1])*(ld[j-1]+ld[n]-ld[zs-1]));
或者两行:
f[j][i+j-1][0]=min(f[j+1][i+j-1][0]+(z[j+1]-z[j])*(ld[j]+ld[n]-ld[i+j-1]),f[j+1][i+j-1][1]+(z[i+j-1]-z[j])*(ld[j]+ld[n]-ld[i+j-1]));
f[j][i+j-1][1]=min(f[j][i+j-1-1][0]+(z[i+j-1]-z[j])*(ld[j-1]+ld[n]-ld[i+j-1-1]),f[j][i+j-1-1][1]+(z[i+j-1]-z[i+j-1-1])*(ld[j-1]+ld[n]-ld[i+j-1-1]));
完整代码见下:
#include<bits/stdc++.h>
using namespace std;
struct ll{
long long a,b,c,d,e,k,x,y,z;
}v[102345];
bool qp(ll a,ll b){
return a.a<b.a;
}
long long mo=1e9+7,f[1005][1050][5],ld[1000405],lk=0,n,m,z[14045],x[20122];
int main(){
cin>>n>>m;
memset(f,10,sizeof(f));
for(int i=1;i<=n;i++){
cin>>z[i]>>x[i];
ld[i]=ld[i-1]+x[i];
}
f[m][m][1]=0;
f[m][m][0]=0;
for(int i=2;i<=n;i++){
for(int j=1;j<=n;j++){
long long zs=i+j-1;
f[j][zs][0]=min(f[j+1][zs][0]+(z[j+1]-z[j])*(ld[j]+ld[n]-ld[zs]),f[j+1][zs][1]+(z[zs]-z[j])*(ld[j]+ld[n]-ld[zs]));
f[j][zs][1]=min(f[j][zs-1][0]+(z[zs]-z[j])*(ld[j-1]+ld[n]-ld[zs-1]),f[j][zs-1][1]+(z[zs]-z[zs-1])*(ld[j-1]+ld[n]-ld[zs-1]));
}
}
cout<<min(f[1][n][1],f[1][n][0]);
return 0;
}