[置顶] 二分法实战(一)——HangOver问题(POJ1003)

问题模型:

问题:在一张桌子上叠放卡片,如果是一张卡片,这张卡片最多可以向桌子外伸出卡片长度的一半;如果是两张卡片,最下面的一张卡片伸出卡片长度的三分之一,上面的一张伸出卡片长度的一半,则两张卡片伸出桌子的总长度为 1/2 + 1/3 = 5/6;以此内推,N张卡片向外延伸的长度为:
1/2+1/3+1/4+…+1/(n+1),最上面的卡片向外延伸1/2.第二张向外延伸1/3,…最下面的一张向外延伸1/(n+1).如图所示
[置顶] 二分法实战(一)——HangOver问题(POJ1003)_第1张图片

输入

输入由一个或多个测试数据组成,最后一行用0.00表示输入结束,每个测试数据占据一行,是一个3位的浮点数C,最小值0.00,最大值5.20

输出

对每个测试数据C,输出要至少伸出超过C的卡片长度最少要用的卡片的数目。输入样例如下。

解析

由于数据范围很小,可以先计算出截止长度不超过5.20所需的最少卡片数。设total为卡片数,len[i]为前i张卡片向外延伸的长度,则len[i]=len[i-1]+1/(i+1),显然len为递增序列。
注意:由于len的表袁术和被查找的元素X为实数,因此要阉割控制精度误差。设精度delta=e-8(10的-8次方),函数zero来判断元素x与0的比较。

在计算出len数组后,先输入第1个测试数据x,并循环体,每一次循环,使用二分法在len表中查找至少伸出卡片长度x所最少要用的卡片数,并输入下一个测试数据x,直到测试数据0.0。

编码

#include <iostream>
using namespace std;
const int maxn = 300;   //len数组容量
const double delta = 1e-8; //精度


int zero(double x){
    if (x < -delta)
        return -1;
    return x > delta;
}

int main(int argc, char* argv[])
{
    double len[maxn]; //卡片伸出桌子的长度
    int total; //卡片的总数

    len[0] = 0.0;
    //计算出戒指长度不超过5.20所需的最小卡片数量
    for (total = 1; zero(len[total - 1] - 5.20) < 0; total++){
        len[total] = len[total - 1] + 1.0 / double(total + 1);
    }

    double x;
    cin >> x;
    //用二分法在len表中查找不小于z的最少卡片数
    while (zero(x)){
        int l, r;
        l = 0;
        r = total;

        while (l + 1 < r){
            //计算中间值
            int mid = (l + r) / 2; 
            //如果中间元素小于x,则在右区间查找;否则在左区间查找。
            if (zero(len[mid] - x < 0))
                l = mid;
            else
                r = mid;

        }
        cout << r << "cards" << endl;
        cin >> x;
    }

    return 0;
}

测试

你可能感兴趣的:(数据结构,算法,二分法,poj)