Garland POJ1759

投稿日: 更新日:

問題:http://poj.org/problem?id=1759

問題

NN個のランプをワイヤーにぶら下げます。一番左のランプH1H_1の高さはAA、一番右のランプHNH_Nの高さはBBです。ランプの重みにより、ワイヤーはたるみます。この時以下の3つの式が成立します。

H1=AHi=Hi1+Hi+121(1<i<N)HN=BHi0(1iN)\begin{aligned} &H_1 = A \\ &H_i = \frac{H_{i-1} + H_{i+1}}{2} - 1 (1 < i < N) \\ &H_N = B \\ &H_i \geqq 0 (1 \leqq i \leqq N) \end{aligned}

NNAAが与えられるので、これら全ての条件を満たす最小のBBを小数第2位まで求めてください。

解法

与えられた式を変形します。

Hi=Hi1+Hi+1212Hi=Hi1+Hi+12Hi+1=2HiHi1+2\begin{aligned} H_i = \frac{H_{i-1} + H_{i+1}}{2} - 1 \\ 2H_i = H_{i-1} + H_{i+1} - 2\\ H_{i+1} = 2H_i - H_{i-1} + 2 \end{aligned}

H1H_1H2H_2が定まれば、上の漸化式を用いて全てのHHを確定することができます。H1H_1AAと与えられているので、適切なH2H_2を探索すれば良いです。探索には二分探索を用います。H1H_1H2H_2を決めたあと、全てのHiH_iが0以上でるかを判定します。

実装

#include <iostream>
#include <vector>
using namespace std;

int main(){
    int n;
    double a;
    cin >> n >> a;

    double ok = 1e9, ng = -1;
    for(int ii = 0;ii < 100; ++ii){
        double mid = (ok+ng)/2;

        vector<double> h(n);
        h[0] = a;
        h[1] = mid;
        for(int i = 2;i < n; ++i){
            h[i] = 2*h[i-1] - h[i-2] + 2;
        }

        bool valid = true;
        for(int i = 0;i < n; ++i){
            if(h[i] < 0)valid = false;
        }

        if(valid){
            ok = mid;
        }else{
            ng = mid;
        }
    }

    vector<double> h(n);
    h[0] = a;
    h[1] = ok;
    for(int i = 2;i < n; ++i){
        h[i] = 2*h[i-1] - h[i-2] + 2;
    }

    printf("%.2f\n", h[n-1]);
    return 0;
}

書いた人

profile_image

お茶の葉

物理とプログラミングが好きな人