题目描述:

近日,项目中偶遇一个有趣的题目,感慨多多,备忘之。抽象出来,大致是:

桌上一共有100个饺子,其中有10个饺子包了硬币,问:连续吃到硬币的期望次数是多少次?

首先,定义一下这里的连续,如果我们将吃饺子的顺序抽象为一个100位的二进制数。并且吃到饺子表示为1,没吃到则为0,那么:
  • 如果一次和第二次吃到,那么可表示为: 110.....,那么这里的连续吃到的次数为1.
  • 如果数字为: ...1111.... ,那么这里连续的4个1表示3次连续,也就是说只要连续,就算1次。

    期望次数,也就是说我们需要算出0个连续,1个连续,....9个连续。这10个计数。

注:这里的连续其实就是取决于当前位置的前一个位置的状态即可。因此可以用DP来解决

此题目是一个数数的问题,显然可以使用DP来进行求解。

global[i][j][k] : 表示前i个饺子中,已经吃到了j个硬币,并且连续的次数为k。

local[i][j][k] : 表示前i个饺子中,吃到了j个硬币,并且第k次连续发生在第i个位置上。(也就是说第i-1次吃到的也是饺子)。并且连续的次数为k。

  • local[i][j][k] = local[i-1][j-1][k-1] + global[i-3][j-2][k-1]

  • global[i][j][k] = local[i][j][k] + global[i-2][j][k] + global[i-2][j-1][k] + local[i-3][j-2][k-1] + global[i-3][j-1][k]

显然上式以最后一次是否连续作为子问题是不明智的,递推关系式太过复杂。

下面从另一个角度来分析:

以最后两位的状态来决定:

  • 11 : 那就是连续一次,
  • 10 , 01, 00 , 都没有连续,子问题直接递推即可。

    因此,定义如下子问题:

    f[i][j][k][0/1] : 表示前i个饺子中,吃到了j个硬币,并且有k个连续。且最后一个是0/1的次数。

    那么我们要求的就是: f[100][10][k][0] + f[100][10][k][1]; k = {1,2,3,...,9}

    注意:这里的最后一维其实就是一个0/1的记录,当然你也可以使用两个三维数组来表示。

    Python代码实现如下:

def compute(m,n,f,g):
    if n > m: return -1
    for i in range(m+1):
        f[i][0][0] = 1
    for j in range(n+1):
        f[0][j][0] = 0
        g[0][j][0] = 0
    f[0][0][0] = 1
    g[0][0][0] = 1
 
    for i in range(1,m+1):
        for j in range(1,min(i,n)+1):
            for k in range(0,j):
                f[i][j][k] = f[i-1][j][k] + g[i-1][j][k]
                if k != 0: g[i][j][k] = f[i-1][j-1][k] + g[i-1][j-1][k-1]
                else: g[i][j][k] = f[i-1][j-1][k]
 
    cnt = [0 for i in range(n)]
    for k in range(0,n):
        cnt[k] = f[100][10][k] + g[100][10][k]
    print cnt[1:]
 
    allSum = 1.0
    for i in range(91,101):  allSum = allSum * i
    for i in range(1,11): allSum /= i
    print "allSum = ", allSum
 
    print [float(x)/allSum for x in cnt]
    allSum2 = 0
    for i in range(1,n): allSum2 += (i * cnt[i])
    print allSum2/float(allSum)
 
if __name__ == "__main__":
    m = 100
    n = 10
    k = n-1
    f = [[[0 for k in range(k+1)] for j in range(n+1)] for i in range(m+1)]
    g = [[[0 for k in range(k+1)] for j in range(n+1)] for i in range(m+1)]
    compute(m,n,f,g)

结果为: 0.9

由于这个函数在目前的项目中可能会出现多次调用的情况。那么计算次数要尽量低。另一方面,这个内存占用非常大,在项目中n和m的取值大概是10^5。

如何快速有效的实现。

目前的方案是:由于这是一个三位的数组,那么每一维其实是一个平面,那么我隔固定的区间保存这样的一个平面,比如说,保存f[i][j][100], f[i][j][200], ...,这样下去,在计算时,选取最接近的平面,向下推。(因为每一个平面的计算只依赖于上一个平面)。

上述讲法可能有点儿晦涩,类比一个简单的例子,就清晰了:

比如,我们现在要编写一个求解斐波拉契数的函数,这个函数调用次数非常的频繁,那么我们回想到使用备忘录,但是呢,我们现在的内存十分有限,不可能将前面计算过的值全部保存下来。那么我们保存哪些值呢,很简单,因为每一个数之依赖于它的前两个数,因此,我们隔一段区间保存两个数。比如,我们保存 f[1000], f[1001], f[2000], f[2001],f[3000],f[3001],....我们计算f[3076]的时候,直接从f[3000],f[3001]开始算起即可,不需要再从0开始,这样既降低了空间的消耗的同时尽可能地减少时间的消耗。

其实这就是一个一维的情况,每次保存的是两个数。上面的三维矩阵,每次保存的是一个二维的数组。

Final words:

  • 这里调BUG时,对Python这种动态语言又进了一步,下面的代码正确吗?自己试试吧:

      tmp = [0 for i in range(k+1)]
      tmp2 = [tmp[:] for i in range(n+1)]
      f = [tmp2[:] for i in range(m+1)]
      g = [tmp2[:] for i in range(m+1)]

    这样定义f和g两个数组对吗?

  • DP的子问题定义是technique。子问题定义的好坏直接影响递推式的复杂程度。

项目中的有趣题目 -- 吃饺子问题相关推荐

  1. 如何在比赛和项目中培养一个好的探索性分析(EDA)思维 —— 翻译自kaggle一位有趣的分享者

    文章目录 前言 1.So... 我们期待从中知道些什么 2.第一件事,分析"SalePrice" 3.SalePrice,她的身体和她的兴趣爱好 4.SalePrice与类别特征的 ...

  2. 【Go进阶】如何让你Go项目中日志清晰有趣-Zap日志库

    本文先介绍了Go语言原生的日志库的使用,然后详细介绍了非常流行的Uber开源的zap日志库,同时介绍了如何搭配Lumberjack实现日志的切割和归档. Zap日志库在Go语言项目中的使用 在许多Go ...

  3. 在一个软件开发项目中进行实际日程安排的十二点提示(转)

    Laura Rose , QE Manager, Rational<?XML:NAMESPACE PREFIX = O /> <?XML:NAMESPACE PREFIX = ST1 ...

  4. 32个Python爬虫项目让你一次吃到撑

    今天为大家整理了32个Python爬虫项目. 整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心.所有链接指向GitHub,祝大家玩的愉快~O(∩_∩)O WechatSogou [1] ...

  5. python爬虫-资源 | 32个Python爬虫项目让你一次吃到撑

    原标题:资源 | 32个Python爬虫项目让你一次吃到撑 作者 | Fendo 来源 | CSDN 今天为大家整理了32个Python爬虫项目. 整理的原因是,爬虫入门简单快速,也非常适合新入门的小 ...

  6. 吃饺子不如撸代码!今年冬至 workshop 干货都在这了

    2018年的冬至,除了传统的吃饺子,作为开发者,我们还有什么特别的活动呢? 当然有啦!12月22日,中国专业IT社区CSDN在中关村创业大街为广大开发者带来了一场精彩绝伦的区块链实战开发Worksho ...

  7. 2022年广东省安全员B证第三批(项目负责人)上岗证题目及模拟考试

    题库来源:安全生产模拟考试一点通公众号小程序 2022保育员(中级)考试100题系保育员(中级)复审题库新版习题库!2022保育员(中级)复训题库及在线模拟考试根据保育员(中级)最新教材汇编.保育员( ...

  8. 软件开发项目中进行实际日程安排

    转自:http://www.ibm.com/developerworks/cn/rational/rationaledge/content/sep05/rose/ 你是否有足够的能力领导一个软件开发项 ...

  9. 作为一名Java程序员,我为何不在生产项目中转向Go?

    自Google在2009年发布Go语言的第一个正式版之后,这门语言就以出色的语言特性受到大家的追捧,尤其是在需要高并发的场景下,大家都会想到是不是该用Go.随后,在国内涌现出了一批以七牛为代表的使用G ...

最新文章

  1. 【机器视觉】Qt集成Halcon开发环境详解(一)
  2. 循环结构_for循环
  3. java 爬虫_Java原生代码实现爬虫(爬取小说)
  4. [objective-c] 08 - 内存管理
  5. Java快速入门学习笔记8 | Java语言中的数组
  6. WebApi 数据保护操作未成功。这可能是由于未为当前线程的用户上下文加载用户配置文件导致的。当线程执行模拟时,可能会出现此情况。,ExceptionType:System.Security....
  7. php 计算每年春节日期,动态显示2019年农历春节倒计时—2019年1月21日23时45分
  8. OpenCV-Python实战(番外篇)——利用 K-Means 聚类进行色彩量化
  9. html网页的配色,css页面网页配色
  10. Tri-training, 协同训练算法
  11. word上下的横线怎么去掉_word中去掉页面上的横线 word页面横线怎么去掉
  12. 全球网络安全行业全景图与中国网络安全行业全景图-2022
  13. windbg 查看结构体_windbg常见命令
  14. 云呐|常用的固定资产盘点方法有哪些
  15. H5地理定位、百度地图使用
  16. 香港中文大学计算机专业学费,香港中文大学研究生专业学费是多少?
  17. 【TcaplusDB知识库】Tcaplus-JDBC开发入门指南
  18. Linux磁盘挂载问题 ***is apparently in use by the system; will not make a filesystem here!
  19. 根据HSV阈值对图像二值化
  20. 删除文件时显示该文件不在此文件夹中的原因

热门文章

  1. 使用face++接口实现人脸相似度比对
  2. css字体设置为 左上角/右上角/左下右下 显示
  3. 对话系统最新进展-17篇EMNLP 2021论文
  4. 如何通过API查询指定的手机号或邮箱查询是否注册支付宝以及真实姓名?
  5. 新手学Python之学习官网教程(六: Modules)
  6. NLP 算法工程师面试问答-DeepLearningAlgorithm
  7. SpringBoot启动时报错
  8. 数据分析与AI(五)pandas的数据拼接操作/美国各州人口分析/苹果历年股票曲线图
  9. 等保测评方案怎么做?按照这个流程来,轻松又省心!
  10. 计算机408看不懂?那是你还不知道这套学习方法和资源