两个玻璃球和100层楼的问题

(http://hi.baidu.com/ajdo/blog/item/f0c292ed8cf6b05d78f055ba.html)

给你两个玻璃球,有一座100层的大厦,用最少的实验次数找出临界层,即从那一层抛下玻璃球,玻璃求刚好不破,再上一层就回破碎.玻璃球碎了之后,不可再用哦.


#include "stdio.h"
#include "string.h"
const int INF = 200000000;
const int maxN = 110;
int f[maxN][maxN][maxN];
int n, k;
int
find(int l, int r, int k)
{
if (l > r)
{
return 0;
}
if (k == 1)
{
return r - l + 1;
}
if (l == r)
{
return 1;
}
if (f[l][r][k] != -1)
{
return f[l][r][k];
}
int mid;
int left, right, t;
f[l][r][k] = INF;
for (mid = l; mid <= r; ++mid)
{
left = find(l, mid - 1, k - 1);
right = find(mid + 1, r, k);
t = left > right ? left : right;
f[l][r][k] <?= t;
}
return ++f[l][r][k];
}
int
main()
{
memset(f, -1, sizeof(f));
while (scanf("%d %d", &n, &k) == 2)
{
printf("%d\n", find(1, n, k));
}
return 0;
}

结果是14


分析:

题目的意思应该是
找出一个固定的方案A, 使得对于目标t为任意[1,100]里的数的时候, 找出t要扔的最多的次数 最小
因为t不同的时候, 方案A要扔的次数不一定一样, 我们就是要使得这个最多的次数最小
动态规划就好了
F(l,r,k)为 确定目标t是否在[l,r]中且手上有k个棋子的最少扔子次数, 有状态转移方程: / (r-l+1) (k = 1)F(l,r,k) = | 1 (l = r) | 0 (l > r) \ 1+min{max{F(l,mid-1,k-1),F(mid+1,r,k)}} (l<=mid<=r)
所求就是F(1,100,2).
Please correct me if I'm wrong.

2. 基本概念:
大前提:
1)临界层
使玻璃球破碎的最低的楼层。
2)最优解
100层中任意一层都可能是临界层,c(n)表示临界层为n层时该算法需要的测试次数,那么(c(1)+c(2)+...+c(100))/100为平均测试次数,平均测试次数最小的算法既为最优算法。
定理1:
若:a(n,m)表示有m个玻璃球,n层楼时的最优算法的测试平均值
则:a(n,m)<=a(n,m-1) a(n,m)<=a(n+1,m)
例:a(100,2)<=a(100,1) a(100,2)<=a(101,2)
定理2:
必然存在1<=k<n使
a(n,m)=(a(k,m-1)*k+a(n-k,m)*(n-k))/n +1
例如:a(100,2)为2个玻璃球100层的最小平均测试次数。因为第一次测试点选择100层是无意义的(必然会碎,所以无任何测试价值),所以第一次测试点k是1-99中的一个数。测试结果只有两种,碎了或没碎。
如果碎了,则临界层为[1,k]中的一个数,由于减少了一个测试球,所以接下来的测试等价于求解用m-1=1个球测试k个层的最优算法,其最小测试平均值为a(k,1)
若没碎,则临界层为[k+1,100]中的一个数,当然测试球没有减少,后续的测试等价于求解用2个球测试(100-k)个层的最优算法,其最小测试平均值为a(100-k,2)。
所以:必定存在k,使(因为已经测试了一次,所以a(k,1)要加1,同理a(100-k,2)+1)
a(100,2)=((a(k,1)+1)*k+(a(100-k,2)+1)*(100-k))/100=(a(k,1)*k+a(100-k,2)*(100-k))/100+1
定理3:
设t(n,m)=a(n,m)*n,那么t(n,m)最小的算法即为最优算法
同理
必然存在1<=k<n使
t(n,m)=t(k,m-1)+t(n-k,m) +n
本题m=2,则
t(n,2)=t(k,1)+t(n-k,2)+n
====================================================
显然t(1,0)=t(1,1)=t(1,2)=0
n=2时,k只能为1
t(2,2)=t(1,1)+t(1,2)+2=2
t(2,1)=t(1,0)+t(1,1)+2=2
n=3时,k=1 or 2用穷举法算出口k=1时最小(k=2时同样最小,取一个即可),记为k[3]=1
t(3,2)=t(1,1)+t(2,2)+3=0+2+3=5
t(3,1)=t(1,0)+t(2,1)+3=5
n=4时,k=1 , 2 or 3 用穷举法算出口k=2时最小,记为k[4]=2
t(4,2)=t(2,1)+t(2,2)+4=2+2+4=8
t(4,1)=t(1,0)+t(3,1)+4=9
循环至100时,得出k=14时最小,记为k[100]=14

t(100,2)=t(14,1)+t(100-14,2)+100
到这里方案已经出来了
首先在14层测试
若碎,执行用1球测14层楼的方案,即从1层开始逐层测试
若不碎,执行用2球测86层的方案,测试层为14+k[86]=14+13=27
最后在电子表格中演算了一下:若一直不碎,依次所选的测试楼层为
14,13,12,11,10,9,8,7,5,4,3,2,1
其中数字代表每次上升的楼层数。
t(100,2)=1030
临界层为任意楼层的情况下,测试的平均次数为1030/100=10.3
3.投掷次数分布不均。按最坏情况估计,这种方法就多做了几次。为了使最坏情况的投掷数最小,我们希望无论临界段在哪里,总的投掷数都不变,也就是说将投掷数均匀分布。
接下来的解决方案就很容易想出了:既然第一步(确定临界段)的投掷数增加不可避免,我们就让第二步(确定临界层)的投掷数随着第一步的次数增加而减少。第一步的投掷数是一次一次增加的,那就让第二步的投掷数一次一次减少。假设第一次投掷的层数是f,转化成数学模型,就是要求f+(f-1)+...+2+1>=99,即f(f+1)/2>=99,解出结果等于14。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值