动态规划解抛鸡蛋(玻璃球)问题

来源:互联网 发布:淘宝天猫搜索排名规则 编辑:程序博客网 时间:2024/06/11 22:05

【转自】http://www.cppblog.com/xiaoyisnail/archive/2009/09/18/96638.html

动态规划解抛鸡蛋(玻璃球)问题

    昨天早上看了题经典老题,抛玻璃球,也有的版本是抛鸡蛋,可惜昨天早上愣是没做出来,下午忙别的事去了,到了晚上看了ChinaUnix上的一篇讨论帖才知道如何解,事实上我一开始对题目的理解就错了,于是根本没有想到用DP。今天总算有时间整理一下思路,并把代码实现出来了。
    题目是这样的:一个100层的大厦,你手中有两个相同的玻璃球。从这个大厦的某一层扔下围棋
子就会碎,用你手中的这两个玻璃围棋子,找出一个最优的策略,来得知那个临界层面。
    这里的最优策略指的是在这种策略下无论哪个临界层面在第几层,测试的次数最少。我一开始就是把题意理解错了,给了一个非最优解,后来看了CU那的讨论后才明白了是用动态规划来做,并可以把题目扩展为n层大厦用k个玻璃球来测试。
    设F(n,k)为用k个玻璃球来测试n层大厦的临界层的最少次数,状态转移方程如下:
    F(n,k)=min{max{F(r,k-1), F(n-r,k)}+1, 1<=r<=n}
    边界条件:F(n,1)=n-1, F(1,k)=F(0,k)=0
    状态转移方程可以这样来考虑,假设在n层楼中的第r层抛一次(对应方程中的"+1"),会有两种情况发生:
    (1)玻璃球碎,说明在第1到第r层楼中必有一层为临界层,问题转化为一个子问题:求F(r,k-1)
    (2)玻璃球不碎,说明临界层在第r+1层到第n层这n-r层楼中,问题转化为子问题:求F(n-r,k)
    因为考虑的是最坏情况下抛球策略的所需测试次数的最小值,所以取这两种情况中的较大值,并遍历每一个可能的r,取其最小值即得到F(n,k)。
    实现代码如下:
 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <string>
 5 #include <cmath>
 6 #include <iomanip>
 7 #include <vector>
 8 #include <deque>
 9 #include <list>
10 #include <queue>
11 #include <stack>
12 #include <map>
13 #include <algorithm>
14 #include <limits>
15 #include <utility>
16 #include <ctime>
17 #include <bitset>
18 using namespace std;
19 
20 #define MAX_FLOOR 512
21 #define MAX_BALL  100
22 
23 int dp(int n, int k)
24 {
25     if(k<1 || n<1) return -1;    //错误输入
26 
27     if(k==1) return n-1;        //去掉一些trivial case
28     if(n==1) return 0;
29 
30     int M[MAX_BALL][MAX_FLOOR];
31     int i,j,r;
32     int temp, min;
33 
34     for(i=0;i<=k;i++) M[i][0]=M[i][1]=0;    //F(1,k)=F(0,k)=0
35     for(j=2;j<=n;j++) M[1][j]=j-1;            //F(n,1)=n-1
36 
37     /*
38     状态转移方程:
39     F(n,k)=min{max{F(r,k-1)+1, F(n-r,k)+1}, 1<=r<=n}
40     */
41     for(i=2;i<=k;i++)
42         for(j=2;j<=n;j++)
43         {
44             min = numeric_limits<int>::max();
45             for(r=1;r<=j;r++)
46             {
47                 temp = max(M[i-1][r], M[i][j-r])+1;
48                 if(temp<min)
49                     min = temp;
50             }
51             M[i][j] = min;
52         }
53 
54     return M[k][n];//F(n,k)
55 }
56 
57 int main()
58 {
59     int n,k;
60     
61     cin>>n>>k;
62     cout<<dp(n, k)<<endl;
63     
64     return 0;
65 }

input: 100 2  output: 14
input: 300 3  output: 13
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 跑步心肺功能差怎么办 剧烈运动后恶心想吐怎么办 运动后头晕想吐怎么办 跑步后反胃想吐怎么办 长跑后恶心想吐怎么办 离职前请假不批怎么办 酷派x7无限重启怎么办 钢铁雄心3资源多怎么办 汽车智能钥匙没电了怎么办 辐射3食物有辐射怎么办 辐射3玩起来很卡怎么办 辐射3多余的瓶盖怎么办 辐射4开锁太快怎么办 极度恐慌3没子弹怎么办 辐射3道德值低怎么办 辐射3任务做完了怎么办 极限竞速6闪退怎么办 两个睾丸都碎了怎么办 快递退回去了钱怎么办 想登录老公微信怎么办 养狗家里味道大怎么办 实在不想养狗了怎么办 培训完不想干了怎么办 干了几天想离职怎么办 药流开始流血了怎么办 药流期间同房了怎么办 想学韩语可是没基础怎么办 鞋子多买了一双怎么办 胳膊抻着了怎么办妙招 胳膊抻筋了 很疼怎么办 干活胳膊抻筋了怎么办 胳膊上的筋扭了怎么办 一岁宝宝脖子歪怎么办 3岁宝宝轻微斜颈怎么办 2岁宝宝轻微斜颈怎么办 肩膀劳损痛的厉害怎么办 颈后面有个囊肿怎么办 扭腰了怎么办有偏方吗 跑步机点加油了怎么办 高二了英语30分怎么办 苍蝇往人身上飞怎么办