1028 wyh的问题 区间DP变式

链接:https://ac.nowcoder.com/acm/contest/24213/1028
来源:牛客网

题目描述

我国现在能源消耗非常严重,现在政府有这样一个工作,每天早上都需要把一些路灯关掉,但是他们想让在关闭的过程中所消耗的能源是最少的,负责路灯关闭的工作人员以1m/s的速度进行行走,假设关闭路灯的时候不需要花费任何的时间,请你编写一个程序,计算在给定路灯位置和每个路灯的消耗能源的多少,求出当所有路灯关闭的时候所需要的最少能量

输入描述:

多组测试数据循环输入
每组测试数据第一行:N表示路灯的数量 (2<=N <=1000)
第二行:V表示开始关灯的路灯号码。 (1<=V<=N)
接下来的N行中,每行包含两个用空格隔开的整数D和W,用来描述每盏灯的参数
D表示该路灯到原点的距离 (用米为单位来表示),
W表示灯泡的功率,即每秒该灯泡所消耗的能量数。(0<=D<=1000,0<=W<=1000)
路灯按照顺序给出,起始位置的那盏灯不算消耗的电能里面

输出描述:

输出一个整数,即消耗能量之和的最小值。
示例1

输入

复制
4
3
2 2
5 8
6 1
8 7

输出

复制
56

说明

对于样例,我一开始在第三个路灯的位置,即在6位置
第1s的时候去5把第二盏灯关闭,消耗电能8
然后去第四盏灯,第四盏灯亮的时间是4s 所以消耗电能28
最后去关第一盏灯第一盏灯亮的时间是10s 所以消耗电能20
最后总和为8+28+20=56

分析

这题不像线性DP,可以通过一次枚举的方式得到所有答案,

也不像背包,是一个取数的问题

也不像普通的区间DP,这题有了一个起点 和 距离成本

但这题是可以从小区间的状态推出大区间的状态,所以只要将距离成本纳入考虑即可

由于每秒钟还没被关掉的灯都会有自己的消耗,所以可以用一个前缀和预处理出所有路灯的功率,就能轻松表示每秒钟还没被关掉的路灯的消耗了

设状态:dp[i][j][k] 表示的是i到j区间内,最后一步往(k == 0? 左:右;)走,所得到的最小权值

状态转移方程:

dp[i][j][0] = min({dp[i][j][0],dp[i+1[j][0] + (a[i+1]-a[i]) * (sum[n] - sum[r] + sum[l]),dp[i+1][j][1] + (a[j] - a[i]) * (sum[n] - sum[r] + sum[l])});

dp[i][j][1] = min({dp[i][j][1],dp[i][j-1][1] + (a[j] - a[j-1])* (sum[n] - sum[r-1] + sum[l-1]),dp[i][j-1][0] + (a[j] - a[i]) * (sum[n] - sum[r-1] + sum[l-1)});

最后答案就是:min(dp[1][n][0],dp[1][n][1]);

//-------------------------代码----------------------------

//#define int LL
const int N = 1100;
int n,st;
int dp[N][N][2];
int a[N],b[N],sum[N];
void solve()
{
while(cin>>n) {
memset(dp,0x3f,sizeof dp);
int st;
cin>>st;
for(int i = 1;i<=n;i++) {
cin>>a[i]>>b[i];
sum[i] = sum[i-1] + b[i];
}
dp[st][st][0] = dp[st][st][1] = 0;
for(int l=st;l>=1;l--){
for(int r=st;r<=n;r++){
int tot=sum[n]-sum[r]+sum[l];
int oto = sum[n] - sum[r-1] + sum[l-1];
// dp[i][j][0]=min(dp[i+1][j][0]+(d[i+1]-d[i])*(sum[n]-sum[j]+sum[i]),dp[i+1][j][1]+(d[j]-d[i])*(sum[n]-sum[j]+sum[i]));
// dp[i][j][1]=min(dp[i][j-1][1]+(d[j]-d[j-1])*(sum[n]-sum[j-1]+sum[i-1]),dp[i][j-1][0]+(d[j]-d[i])*(sum[n]-sum[j-1]+sum[i-1]));
dp[l][r][0]=min(dp[l][r][0],min(dp[l+1][r][0]+(a[l+1]-a[l])*tot,dp[l+1][r][1]+(a[r]-a[l])*tot));
dp[l][r][1]=min(dp[l][r][1],min(dp[l][r-1][1]+(a[r]-a[r-1])*oto,dp[l][r-1][0]+(a[r]-a[l])*oto));
}
}
cout<<min(dp[1][n][1],dp[1][n][0])<<endl;
}
}

signed main(){
clapping();TLE;

// int t;cin>>t;while(t -- )
solve();
// {solve(); }
return 0;
}

/*样例区


*/

//------------------------------------------------------------

posted @ 2022-07-10 19:35  er007  阅读(25)  评论(0编辑  收藏  举报