「 COGS 2240 」 X 「 Luogu P2885 」 架设电话线

Posted bljfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「 COGS 2240 」 X 「 Luogu P2885 」 架设电话线相关的知识,希望对你有一定的参考价值。

解题思路

首先很容易就想到了一个二维的朴素的 $dp$。

设 $dp[i][j]$ 表示第 $i$ 个位置的电话线杆的高度为 $j$ 时的最小花费,就需要枚举第 $i$ 个电话线杆、第 $i$ 个电话线杆的高度 $j$、第 $i-1$ 个电话线杆的高度 $k$。

状态转移方程如下

$$dp[i][j] = min {dp[i-1][k]+|j-k| imes c + (j-h[i])^2}$$

但是这样的 $dp$ 过不了这题的数据范围。这个 $dp$ 的时间复杂度是 $ ext{O}(n imes h^2)$。

所以需要考虑别的方法进行优化。

我们试着只枚举一个 $j$,而不是枚举 $j$ 和 $k$。

首先来说这个 $j$,它既是我们枚举的第 $i$ 个电话线杆的高度也是我们枚举的第 $i-1$ 根电话线杆的高度。$i-1$ 要相对 $i$ 产生影响,那么 $j$ 一定是大于 $h[i-1]$ 的。

我们在 $jge h[i-1]$ 时取一个最小值,同时又要消去绝对值的影响。这就要看 $j$ 的枚举顺序了。如果是正序枚举那么之后的j一定会大于当前的j,之后的 $j-$ 现在的 $j$,是正的。

所以现将现在的 $j imes c$ 减掉。到时候进行扩展的时候在将那时的 $j imes c$ 加上。就等价于加上了绝对值。倒序枚举只是换了下顺序,道理还是一样的就不再过多的解释。

再来看 $jge h[i]$ 的时候,这时的高度为 $j$ 的第 $i$ 根电话线杆已经能够被更新了。所以就将其更新。

然后再做一遍倒序枚举因为还要考虑 $i-1$ 比 $i$ 高的情况。

 

附上代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
inline int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < 0 || c > 9) {if(c == -) f = -1; c = getchar();}
    while (c <= 9 && c >= 0) {x = x*10 + c-0; c = getchar();}
    return x * f;
}
const int maxn = 1e5+3, INF = 1e9;
int n, c, h[maxn], f[maxn][103], Ans = INF;
int main() {
    freopen("phonewire.in", "r", stdin);
    freopen("phonewire.out", "w", stdout);
    n = read(), c = read();
    for(int i=1; i<=n; i++)
        for(int j=0; j<=100; j++)
            f[i][j] = INF;
    for(int i=1; i<=n; i++)
        h[i] = read();
    for(int i=h[1]; i<=100; i++) f[1][i] = (i-h[1]) * (i-h[1]);
    int minn;
    for(int i=2; i<=n; i++) {
        minn = INF;
        for(int j=0; j<=100; j++) {
            if(j >= h[i-1]) minn = min(minn, f[i-1][j] - c*j);
            if(j >= h[i]) f[i][j] = min(f[i][j], minn + c*j + (j-h[i]) * (j-h[i]));
        }
        minn = INF;
        for(int j=100; j>=0; j--) {
            if(j >= h[i-1]) minn = min(minn, f[i-1][j] + c*j);
            if(j >= h[i]) f[i][j] = min(f[i][j], minn - c*j + (j-h[i]) * (j-h[i]));
        }
    }
    for(int i=0; i<=100; i++) Ans = min(Ans, f[n][i]);
    printf("%d", Ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

 

以上是关于「 COGS 2240 」 X 「 Luogu P2885 」 架设电话线的主要内容,如果未能解决你的问题,请参考以下文章

luogu cogs 油滴扩展

cogs luogu 单词接龙

luogu cogs 421. HH的项链

cogs luogu [NOIP2011] 选择客栈

cogs luogu 2105. [NOIP2015] 信息传递

cogs luogu 珠心算测试noip2014 普及组