问题模型:
问题:在一张桌子上叠放卡片,如果是一张卡片,这张卡片最多可以向桌子外伸出卡片长度的一半;如果是两张卡片,最下面的一张卡片伸出卡片长度的三分之一,上面的一张伸出卡片长度的一半,则两张卡片伸出桌子的总长度为 1/2 + 1/3 = 5/6;以此内推,N张卡片向外延伸的长度为:
1/2+1/3+1/4+…+1/(n+1),最上面的卡片向外延伸1/2.第二张向外延伸1/3,…最下面的一张向外延伸1/(n+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;
}