zoukankan      html  css  js  c++  java
  • 「 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;
    }
  • 相关阅读:
    SimpleDateFormat解析的时区问题
    linux之cp/scp命令+scp命令详解
    java.net.SocketException: java.security.NoSuchAlgorithmException
    Gradle使用手册(一):为什么要用Gradle?
    js_实用
    exp.validate.js
    MySQL实用技巧
    MongoDB 用户配置
    js 图片处理 Jcrop.js API
    MySQL连接池
  • 原文地址:https://www.cnblogs.com/bljfy/p/9582353.html
Copyright © 2011-2022 走看看