Vijos-p1150 (dynamic programming + interval dp)

Turn off the street lights

description

A certain village has installed n street lamps on a route, and the power of each lamp is large or small (that is, how much electricity is consumed in the same period of time). Lao Zhang lives next to a certain street lamp in the middle of this road. His job is to turn off these street lamps one by one at dawn every morning.

In order to save electricity bills in the village, Lao Zhang recorded the location and power of each street lamp. Every time he turned off the lights, he would turn them off as soon as possible, but Zhang didn't know how to turn off the lights to save electricity the most. Every day he turns off the street light where he is at dawn, and then he can turn off the lights either left or right. At first he thought that he would first calculate the total power of the street lights on the left and then the total power of the street lights on the right, and then choose to turn off the power side first, and then turn back to turn off the other side street lights, but this is not the case, because it is off. A proper U-turn in the process may save you a little bit.

Now it is known that Lao Zhang’s walking speed is 1m/s, the position of each street light (is an integer, that is, the distance from the starting point of the route, unit: m), power (W), the time it takes Lao Zhang to turn off the lights is very short and can be ignored Excluding.

Please compile a program for Lao Zhang to arrange the order of turning off the lights so that all lights consume the least power from the moment Lao Zhang starts turning off the lights (the power will no longer be consumed after the lights are turned off).

format

Input format

The first line is two numbers n (0<n<50, which means the total number of street lights) and c (1<=c<=n the street lamp number where Lao Zhang is located); the
next n lines have two data in each line , Represents the position and power of the first to nth street lights.

Output format

One piece of data, that is, the minimum power consumption (unit: J, 1J=1W·s).

Example 1

Sample input 1

5 3 
2 10
3 20
5 20
6 30
8 10

Sample output 1

270

limit

1s per test point

prompt

The order of turning off the lights at this time is 3 4 2 1 5

Problem solving

The portal
directly refers to the idea of ​​the boss:

/*
经典好题~一个dp必学题叭~~
首先我们要想怎么样才能完整表示一个状态~
我们可以看到的
如果去关灯关掉了区间[l,r]的灯
那么最后关的一盏不是l就是r
所以我们可以想到用这样一个状态表示
f[l][r][k]表示关掉区间[l,r]的所有灯所需要的最小代价
其中k=0表示现在人在l即最后关的灯是l
k=1表示现在人在r即最后关的是r这盏灯
这样就设计出了一个正确无误的状态
先考虑初值
f[i][i]就是从起始位置直接到i开i灯的代价
那么我们来考虑状态转移
我们知道f[l][r][0]表示的是最后关掉了l这盏灯使得[l,r]全部都关了
那么对应的上一个状态必然是已经关掉了[l+1,r]区间所有的灯
那么我们就要考虑到到底是f[l+1][r][0]转移过来更优还是f[l+1][r][1]更优
即考虑到了左右两种完全的情况
那么很容易有状态转移
f[i][j][0]=min(f[i+1][j][0]+(sump-(s[i+1][j]))*getd(i,i+1),
               f[i+1][j][1]+(sump-(s[i+1][j]))*getd(i,j));
其中我们已经预处理出sump表示所有灯总功率
s[i]表示1...i的所有灯的功率然后用前缀和可以算出s[i+1][j]
这个转移仔细理解一下就好了
同理就可以得出f[i][j][1]的转移
递推的时候外层循环枚举长度内层循环枚举起点
最后取f[1][n][0]和f[1][n][1]的更优值就好了~
时间复杂度O(n^2)
可以直接秒杀~
*/

AC code

#include <algorithm>  //关路灯
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 52;
int n, c;
int x[maxn], w[maxn], sump;
int dp[maxn][maxn][2], s[maxn];
// dp[i][j] 选择区间[i, j]时, 最小消耗
// time[i][j] 表示从i到j的时间
// s[i]功率前缀和

int getd(int a, int b) {
    
     return abs(x[b] - x[a]); }

void DP() {
    
    
    memset(dp, 0x3f, sizeof(dp));
    for (int i = 1; i <= n; i++)  //区间长度为1时
        dp[i][i][0] = dp[i][i][1] = abs(x[i] - x[c]) * sump;

    for (int l = 2; l <= n; l++) {
    
    
        for (int i = 1; i + l - 1 <= n; i++) {
    
    
            int j = i + l - 1;
            dp[i][j][0] =
                min(dp[i + 1][j][0] + (sump - (s[j] - s[i])) * getd(i, i + 1),
                    dp[i + 1][j][1] + (sump - (s[j] - s[i])) * getd(i, j));
            // s[j] - s[i] 表示区间[i + 1, j]的功率和
            dp[i][j][1] = min(
                dp[i][j - 1][0] + (sump - (s[j - 1] - s[i - 1])) * getd(i, j),
                dp[i][j - 1][1] + (sump - (s[j - 1] - s[i - 1])) * getd(j - 1, j));
        }
    }
    cout << min(dp[1][n][0], dp[1][n][1]) << endl;
}

int main() {
    
    
    cin >> n >> c;
    for (int i = 1; i <= n; i++) {
    
    
        cin >> x[i] >> w[i];
        sump += w[i];
        s[i] = s[i - 1] + w[i];
    }

    // s[i][j] = s[j] - s[i - 1];
    DP();

    system("pause");
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_45349225/article/details/109551535