晚上无聊的时候把以前的<程序员>杂志拿出来see see,于是就看到了这个算法题.这文章之前也看过,但当时稍微想了一下就溜过去了.今天看的时候突然产生了一些疑问,于是动手写了几行代码测试了下,结果发现文章中的说法并不完全対.
哦,讲了这么久,忘了说这个题在杂志的第65页的第二题.
注意: 原文并没有给出最优策略 的定义,我这儿根据原文的意思考虑的是这样一种策略:
给出一种策略,使得在最坏的情况下,测试的次数最少
下面是我写的代码:(动态规划算法,时间复杂度O(N^2))
java 代码
- /**
- 原题: 有一个100层高的大厦,你手中有两个相同的玻璃围棋子。从这个大厦的某一层扔下围棋子就会碎,用你手中的这两个玻璃围棋子,找出一个最优的策略,来得知那个临界层面。
- 算法(递归):
- 记为n层楼时最少要测试的次数为f(n),则:
- 1. f(1) =0;
- 2. 考虑n+1时,若第一个棋子从第k层扔下,此时分两种情况
- a. 碎了. 则临界值不大于k,由于只剩一颗棋,只能从第1层开始往上测试,最多需再测试k-1次(此种情形共测试了k次)
- b. 没碎. 则临界值在k之上,此时还剩2颗棋,可归结到f(n+1-k)的情形(此种情况共测试了1+f(n+1-k)次)
- f(n+1) = min{ max{k,1+f(n+1-k)}: 1<=k<=n+1}
- @author Eastsun
- @version 1.0 2007/5/5
- */
- import java.util.*;
- public class Best{
- private static Map map = new HashMap();
- //求n层楼时最少用的次数
- public static int min( int n){
- if (n< 0 ) throw new IllegalArgumentException();
- if (n<= 1 ) return 0 ; //n<=1时,为了方便起见,这里记min(0) =0
- Integer s =map.get(n);
- if (s!= null ) return s;
- int min =n; //一个上界(这是i取n次的情形): n
- for ( int i= 1 ;i
- int t1 = 1 + min(n-i); //没碎,递归求解
- int t2 =t1>i?t1:i; //两种情况的最坏情形
- if (min>t2) min =t2;
- }
- map.put(n,min);
- return min;
- }
- private static List list = new LinkedList(); //用于保存求解路径
- /**
- 打印出测试路径
- */
- public static void solve( int n){
- if (n< 0 ) throw new IllegalArgumentException();
- if (n<= 1 ){
- ListIterator iter =list.listIterator();
- if (!iter.hasNext()) return ;
- System.out.print(iter.next());
- while (iter.hasNext()) System.out.print( " -> " +iter.next());
- System.out.println();
- return ;
- }
- int min =min(n);
- for ( int i= 1 ;i<=n;i++){
- int t1 = 1 +min(n-i);
- int t2 =i>t1?i:t1;
- if (t2==min){
- list.add(i);
- solve(n-i);
- list.remove(list.size()- 1 );
- }
- }
- }
- public static void main(String[] args){
- System.out.println( "Min :" +min( 100 )); //注意:有很多组结果
- solve( 100 );
- }
- }
运行程序可以看出,对于n=100的情形,存在很多种最优策略,第一次测试选择的楼层可以是从8到14的任意一层.
ps:贴上去的代码有点走样,请下载附件