Dancepted

Dancing Acceped!

P1220 关路灯 (区间dp)

题目链接:传送门

题目大意:

  总共有N盏灯,老张从点C(1 ≤ C ≤ N)开始关灯(关灯不需要等待时间,C点的灯直接关掉),与此同时灯开始烧电(已知功率Pi)。

  老张每次可以往左走关最近的灯或者往右走关掉最近的灯,耗时等于距离。问最少的烧电量。

  1 ≤ N ≤ 50。

思路:

状态:

  f[i][j]表示在已经关掉i,i+1,…,j的灯时已经浪费的电量。

  讨论发现如果要转移状态,还需要加一维表示老站当前的位置:

  f[i][j][0]表示老张在位置i,f[i][j][1]表示老张在位置j;

初始状态:

  f[C][C][0] = f[C][C][1] = 0;

  老张一开始可以直接关掉C点的灯。

状态访问顺序:

  更新f[i][j]的时候需要知道f[i+1][j]和f[i][j-1]的状态。

  也就是说从C点开始向两边访问即可。

状态转移方程:

  f[i][j][0] = max(f[i+1][j][0] + 从点i+1走到点i所花费的时间 * 还没关掉的灯的总功率,

           f[i+1][j][1] + 从点j走到点i所花费的时间 * 还没关掉的灯的总功率)

  f[i][j][1] = max(f[i][j-1][0] + 从点i走到点j所花费的时间 * 还没关掉的灯的总功率,

           f[i][j-1][1] + 从点j-1走到点j所花费的时间 * 还没关掉的灯的总功率)

 

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAX_N = 55;
const ll INF = 0x3f3f3f3f3f3f3f3f;

int N, C;
int pos[MAX_N];
ll P[MAX_N], sum[MAX_N], f[MAX_N][MAX_N][2];// 0 表示停在左端,1 表示停在右端

void dp()
{
    for (int i = C; i >= 1; i--) {
        for (int j = C; j <= N; j++) {
            if (i == C && j == C) {
                f[i][j][0] = f[i][j][1] = 0;
                continue;
            }
            // (i+1, j) -> (i, j)
            if (i+1 <= C) {
                if (f[i][j][0] > f[i+1][j][0] + (pos[i+1] - pos[i]) * (sum[N] - sum[j] + sum[i])) {
                    f[i][j][0] = f[i+1][j][0] + (pos[i+1] - pos[i]) * (sum[N] - sum[j] + sum[i]);
                }
                if (f[i][j][0] > f[i+1][j][1] + (pos[j] - pos[i]) * (sum[N] - sum[j] + sum[i])) {
                    f[i][j][0] = f[i+1][j][1] + (pos[j] - pos[i]) * (sum[N] - sum[j] + sum[i]);
                }
            }
            // (i, j-1) -> (i, j)
            if (j-1 >= C) {
                if (f[i][j][1] > f[i][j-1][0] + (pos[j] - pos[i]) * (sum[N] - sum[j-1] + sum[i-1])) {
                    f[i][j][1] = f[i][j-1][0] + (pos[j] - pos[i]) * (sum[N] - sum[j-1] + sum[i-1]);
                }
                if (f[i][j][1] > f[i][j-1][1] + (pos[j] - pos[j-1]) * (sum[N] - sum[j-1] + sum[i-1])) {
                    f[i][j][1] = f[i][j-1][1] + (pos[j] - pos[j-1]) * (sum[N] - sum[j-1] + sum[i-1]);
                }
            }
        }
    }
    cout << min(f[1][N][0], f[1][N][1]) << endl;
    return;
}

int main()
{
    cin >> N >> C;
    sum[0] = 0;
    for (int i = 1; i <= N; i++) {
        scanf("%d%lld", pos+i, P+i);
        sum[i] = sum[i-1] + P[i];
    }
    for (int i = C; i >= 1; i--) {
        for (int j = C; j <= N; j++) {
            f[i][j][0] = f[i][j][1] = INF;
        }
    }
    dp();
    return 0;
}
/*
4 3
2 10000
3 10
4 100
5 200

4 3
2 10000
3 200
4 100
5 10
*/
View Code

 

posted on 2018-10-17 23:24  Danceped  阅读(220)  评论(0编辑  收藏  举报

导航