zoukankan      html  css  js  c++  java
  • 数羊问题

    有一只羊,它的寿命是5年,在第二年和第四年能够产下小羊。请问第N年时,羊群里有多少只羊?

    题目就这么简单,还有一些附加说明:

    1.羊的寿命可以理解为0-4或者1-5,反正就是它能活5x365天,第一次产羊就是1岁(0-4)或2岁(1-5)时。

    2.伟大的灵魂都是雌雄同体的,羊生羊不需要其他羊的帮助。

    3.别跟我说心算……当N等于几百万的时候,还能心算吗?

    我把这个问题抽象出来:一只羊在有限的生命力,能够裂变成两只,那么长期来看,羊群的数量应该是指数增长的。这其中一定有一个公式,里面会有乘方次方之类的东西,或者是对数一类的东西,羊群的数量线画出来,就是一个形似 y=x^2 之类的线。

    然而我的脑洞并没有那么大,没法脑补出这个公式,于是我开始写代码:把羊视为一个对象,这个对象在合适的年份会产下小对象,外面套一个for循环,循环年份,即可得到i年份的羊群,然后数一下羊群即可。

    <?php
    class Sheep{
        public $birth;
        public $death;
    }
    
    $sheep = new Sheep;
    $sheep->birth = 0;
    $sheep->death = 5;
    $sheeps = [
        $sheep
    ];
    for($i=0; $i < 10; $i++) { 
        foreach($sheeps as $k=>$sheep){
            if($i-$sheep->birth==1 || $i-$sheep->birth==3){
                $child = new Sheep;
                $child->birth = $i;
                $child->death = $i+5;
                array_push($sheeps, $child);
            }
            if($sheep->death == $i){
                unset($sheeps[$k]);
            }
        }
    }
    echo count($sheeps);

    结果是当i接近40的时候,我的程序就崩掉了,原因是PHP使用了超过128M的内存。

    不论我们把羊对象换成数组,还是抽象成只有出生年份的数组元素,都无法解决这个问题,因为羊的数量是(近似于)指数增长,内存必然是永远不够用的。

    但是不要紧,我认为这个公式本身应当是很简单的,那我们可以用MATLAB去拟合目前计算的结果,是不是能把公式蒙出来。手头没有MATLAB,那就用walframalpha吧。

    这个结果显然是不对的,我又丢进去了更多的参考数,结果也还是不对的——此路不通。

    在我刚验证出这个结果的时候,一个朋友给出了答案,他画了这么一张表:

    横轴的0-11是“羊年纪元”,纵轴是羊年龄,中间的数字是:在这一年时,羊群里X岁的羊,有多少只。

    斜着去看能看到一排1,一排2,3,5,8——斐波那契数列。如果你觉得不够明显,我们假设羊不会死:

    这样足够明显了,在偶数年时,羊数量等于 Fibonacci(YEAR/2+1)。解释下,Fibonacci(n)=1+1+2+3+5+...(一共加n个数)。奇数年时,羊数量等于 SheepCount(YEAR-1)。当然,这是基于羊不会死的假设。

    羊的寿命只有五年,所以要去掉斐波那契数列中一些“前面”的数字。公式变为:

    偶数年:Fibonacci(YEAR/2+1) - Fibonacci(YEAR/2-2)

    奇数年:Fibonacci((YEAR-1)/2+1) - Fibonacci((YEAR-1)/2-1)

    最终代码(因为公式有点“错位”,所以某些部分有一丢丢的增减):

    <?php
    function fib_recursive($n){  
        if($n==1||$n==2){
            return 1;
        }else{
            return fib_recursive($n-1)+fib_recursive($n-2);  
        }  
    }  
    function count_sheep($y){
        $y = $y + 2;
        if($y % 2 == 1){
            return fib_recursive(($y-1) / 2 + 2) - fib_recursive(($y-1) / 2);
        }else{
            return fib_recursive($y / 2 + 2) - fib_recursive($y / 2 - 1);
        }
    }
    for($i = 1; $i < 500; $i++){ 
        echo $i.",".count_sheep($i)."
    ";
    }

    最后,使用PHP计算,在算到60年的时候,每一次计算已经慢成龟,后面每一次都更慢更慢,果然复杂度还是无法避免。。。

  • 相关阅读:
    基于Lumisoft.NET实现的邮件发送功能
    jqueryautocomplete 使用手册
    asp.net访问网络路径方法模拟用户登录
    JavaScript判断浏览器类型及版本
    解决jquery.autocomplete在IE6下被下拉框遮住的问题
    How to resovle aspnet_merge.exe error issue in web deployment project
    敏捷开发之Scrum扫盲篇
    JS 异常: Uncaught RangeError: Maximum call stack size exceeded
    HTTP请求的 转发 重定向 代理
    JS跨域访问 控制
  • 原文地址:https://www.cnblogs.com/missingcat92/p/4707667.html
Copyright © 2011-2022 走看看