大牛生小牛的问题

问题:
          一只刚出生的小牛,4年后生一只小牛,以后每年生一只。现有一只刚出生的小牛,问20年后共有牛多少只?
思路:
          这种子生孙,孙生子,子子孙孙的问题,循环里面还有循环的嵌套循环,一看就知道是第归问题。
于是乎,第一个版本出现:
  public long Compute1(uint years)
        
{
            
//初始化为1头牛
            long count = 1;
            
if (years <= 3)
            
{
                
return count;
            }

            
int i = 4;
            
while (i <= years)
            
{
                
int subYears = i - 3;
                count 
+= Compute1((uint)(subYears));
                i
++;
            }

            
return (long)count;
        }

可是这种循环在循环的做法可要把cpu老兄累坏了,你不信输入一个100年测试一下上面的方法,我等了半天,都没结果,改进一下吧,老牛(牛魔王)和小牛(红孩儿,奶奶的串种了),具有相同的生育能力,他们的生育曲线是一样的,所以小牛可以复用老牛的生育经验亚,这样就解决了重复计算一只牛第n年的时候一共生多少只的问题了,当年龄比较大的时候,明显大大降低cpu的运算次数,下面是基于这种思路的算法
 Hashtable table = new Hashtable();
        
public long Compute(uint years)
        
{
            
//初始化为1头牛
            long count = 1;
            
if (years <= 3)
            
{
                
return count;
            }

            
int i = 4;
            
while (i <= years)
            
{
                
int subYears = i - 3;
                
if (table.ContainsKey(subYears))
                
{
                    count 
= (long)table[subYears];
                }

                
else
                
{
                    count 
+= Compute((uint)(subYears));
                }

                
if (!table.ContainsKey(subYears))
                
{
                    table.Add(subYears, count);
                }

                i
++;
            }

            
return (long)count;
        }
用测试程序测试一下上面的推论吧,结果如下:
1)当输入years比较小的时候,第一种方法耗时短,但两者的时间基本在一个数量级上
2)当输入years比较大的时候,比如40以上的,第二种算法比第一种性能比在100以上,而且输入years越高,性能比越悬殊。
测试结果截图:
20年

50年



源程序以及测试程序:/Files/jillzhang/HowMoneyCows.rar



-------------------------------------------------------
人老了,脑袋不好用了,偶尔用算法来练练脑子,可以防止早衰。呵呵
                                                        jillzhang jillzhang@126.com

作者:jillzhang
出处:http://jillzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2007-09-09 11:00 Robin Zhang 阅读(4746) 评论(47)  编辑 收藏 网摘 所属分类: 算法

  回复  引用    
#1楼2007-09-09 11:17 | 正版阿毅[未注册用户]
继续优化!
最后是一个斐波那切公式。

  回复  引用  查看    
#2楼2007-09-09 12:15 | yAYX      
空间换时间~
  回复  引用  查看    
#3楼2007-09-09 13:11 | Zhuang miao      
数学令我很迷茫
  回复  引用  查看    
#4楼2007-09-09 13:49 | 随风流月      
用 Dictionary(Of TKey, TValue),节省装/拆箱性能。
  回复  引用  查看    
#5楼2007-09-09 13:51 | 布尔      

 

function Cow(year){
    
this.year = year
}

Cow.prototype.GetChilds 
= function(){
    
var arr = []
    
var year = this.year
    
var count = year>=3?(year-3+1):0
    
for(var i=0; i<count; i++){
        
var cow = new Cow(i)
        arr.push(cow)
        arr 
= arr.concat(cow.GetChilds())
    }
    
return arr
}

var cow = new Cow(20)
alert(cow.GetChilds().length)

  回复  引用  查看    
#6楼[楼主]2007-09-09 14:20 | jillzhang      
@随风流月
用List<int>性能比Hashtable稍微好一点

  回复  引用  查看    
#7楼2007-09-09 14:35 | DeViL→Ivy      
不错,学习了
  回复  引用  查看    
#8楼2007-09-09 19:07 | 随风流月      
@jillzhang
不会的... 是 HashSet 快.

  回复  引用  查看    
#9楼2007-09-09 20:02 | Kain      
用Dictionary<T,T>
Hashtable有装箱

  回复  引用  查看    
#10楼2007-09-09 21:11 | 置身珠海,学习与奋斗      
算法,Nice


另外:楼主可真够搞笑 How money cows.

  回复  引用  查看    
#11楼[楼主]2007-09-09 21:23 | jillzhang      
@置身珠海,学习与奋斗
:)

  回复  引用  查看    
#12楼2007-09-10 08:55 | Cat Chen      
1.从数学的角度来说,一看就知道是递推,而不是递归,因为这个数列和Fibonacci数列一差不多。当让你说递归也没错,因为任何递归都能转化为递推。

2.优化递归的第一个思路应该是改为递推。

3.计算Fibnacci数列根本就不需要这么复杂的数据结构,前人都是用数组递推的。

4.最后,最好找到数学公式算,连递推都不要了。

  回复  引用  查看    
#13楼[楼主]2007-09-10 09:01 | jillzhang      
@Cat Chen
受教

  回复  引用  查看    
#14楼2007-09-10 09:05 | Tony Qu      
原来不是生兔子问题嘛,现在咋成生小牛了
  回复  引用  查看    
#15楼2007-09-10 09:08 | hery_2007      
算法都快忘光了
  回复  引用  查看    
#16楼2007-09-10 09:58 | Anders Cui      
当小兔子进化为小牛...
  回复  引用  查看    
#17楼2007-09-10 10:02 | 小陆      
只有生牛没有死牛吗,要不要考虑牛的寿命?
  回复  引用  查看    
#18楼[楼主]2007-09-10 10:15 | jillzhang      
@小陆
可以加上一句呀,一头牛的生命为30年,这样就更有意思了

  回复  引用  查看    
#19楼2007-09-10 11:15 | 無悠      
for (int j = 4;j <= years;j++)
{
table1.Add(j, (long)table1[j - 3] + (long)table1[j - 1]);
}
count = (long)table1[(int)years];
基本时间就一次循环的时间

  回复  引用  查看    
#20楼2007-09-10 11:16 | 無悠      
//初始化为1头牛
long count = 1;
if (years <= 3)
{
return count;
}
table1.Add(1, (long)1);
table1.Add(2, (long)1);
table1.Add(3, (long)1);

  回复  引用  查看    
#21楼2007-09-10 11:56 | 脚印      
从结果分析: 小牛是每年年初出生的

第四年的时候第一头小牛已经发育了一年

  回复  引用  查看    
#22楼2007-09-10 13:09 | 一味      
两个与技术无关的问题。。。。

小牛都是雌性的吗?
牛能存活20年么?

  回复  引用  查看    
#23楼2007-09-10 15:21 | bluebird      
碰到数学题就头疼
  回复  引用    
#24楼2007-09-10 21:45 | 正确答案[未注册用户]
只剩一头老牛。
没得交配的,生个屁啊。嘿嘿。

  回复  引用  查看    
#25楼2007-09-11 09:34 | 三千.℡      
呵呵.没有考虑生出公牛的可能性.所以题目本身也不够严谨啊.

比如可改为:

假设生下的小牛全是母牛,且忽略母牛怀胎的问题,问20年后共有牛多少只?




  回复  引用    
#26楼2007-09-11 09:51 | 领子[未注册用户]
我做的这个应该是最优的了吧。C++

#include <iostream.h>
#define YEAR 50
void main()
{
int a,b,c,sum;

a = 1;
b = 0;
c = 0;

sum = 1;

int i = 4;
while(i <= YEAR)
{
a = a + c;
sum += a;
i++;
if(i>YEAR)
{
break;
}

b = b + a;
sum += b;
i++;
if(i>YEAR)
{
break;
}

c = c + b;
sum += c;
i++;
}

cout<<sum<<endl;
}
20年,50年,100年都是不到1s就出来了。

内容(请不要发表任何与政治相关的内容) 看到这句话,有点想到三四十年代在饭馆里面贴的“莫谈国事”了

  回复  引用    
#27楼2007-09-11 10:47 | limeijun[未注册用户]
樓上的寫得不錯 不過我不懂C++語法 :cout<<sum<<endl; 這句是什麼意思。。

  回复  引用    
#28楼2007-09-11 15:38 | 领子[未注册用户]
输入sum值并换行.
  回复  引用  查看    
#29楼2007-09-12 16:59 | 七年之痒      
递归不是好方法
  回复  引用    
#30楼2007-09-13 09:20 | 0337[未注册用户]
public static long getCount(int year)
{
long y1 = 0;
long y2 = 0;
long y3 = 1;
long y4 = 0;
for (int i = 4; i <= year; i++)
{
y4 = y4 + y3;
y3 = y2;
y2 = y1;
y1 = y4;
}
return y1 + y2 + y3 + y4;
}

  回复  引用    
#31楼2007-09-13 23:23 | 领子[未注册用户]
long Compute(int years)
{
if(years <= 0)
{
return 0;
}

long a,b,c;

a = 1;
b = 0;
c = 0;


int i = 6;
years += 3;
while(i <= years)
{
a += c;
b += a;
c += b;
i += 3;
}

if(years%3 == 0)
{
a = c;
}
else
{
a += c;
if(years%3 == 2)
{
b += a;
a = b ;
}
}
return a;

}

总共用了years次加法.0次乘法.

  回复  引用    
#32楼2007-09-17 16:05 | 桂顺明[未注册用户]
long Compute(int YEARS)
{
long a[128];
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;
int i = 5;
while( i < YEARS)
{
a[i] = a[i-1] + a[i-4];
i++;
}
return a[i-1];
}
这个还不是最简单的,因为我相信应该可以通过数学直接把答案推出来.

  回复  引用  查看    
#33楼2007-09-24 15:06 | 明达      
public static long GetCowAmout(int year)
{
long[] result = new long[year];

for (int i = 0; i < year; i++)
{
result[i] = i < 3 ? 1 : result[i - 1] + result[i - 3];
}

return result[year - 1];
}
hehe,我也来凑凑热闹

  回复  引用  查看    
#34楼2007-09-24 15:18 | 明达      
第01年(共01头牛):1
第02年(共01头牛):0
第03年(共01头牛):0
第04年(共02头牛):1
第05年(共03头牛):1 0
第06年(共04头牛):1 0 0
第07年(共06头牛):1 1 0 0
第08年(共09头牛):1 1 1 0 0 0
第09年(共13头牛):1 1 1 1 0 0 0 0 0
第10年(共19头牛):1 1 1 1 1 1 0 0 0 0 0 0 0
第11年(共28头牛):1 1 1 1 1 1 1 1 1 0 0 0 0
第12年(共41头牛):1 1 1 1 1 1 1 1 1 1 1 1 1
第13年(共60头牛):1 1 1 1 1 1 1 1 1 1 1 1 1
第14年(共88头牛):1 1 1 1 1 1 1 1 1 1 1 1 1

  回复  引用    
#35楼2008-02-02 10:18 | nealbox[未注册用户]
public int NumNiu(int year)
{
int all = year / 4;
if (all == 0)
return 1;
return NumNiu(year - 4) + NumNiu(year - 1);
}

  回复  引用    
#36楼2008-02-02 11:23 | nealbox[未注册用户]
一是全部,二是计算总共生了多少
public int NumNiu(int year)
{
int all = (year-1) / 3;
if (all == 0)
return 1;
return NumNiu(year - 3) + NumNiu(year - 1);
}
public int NumNiu2(int year)
{
int life = 0;
int all = (year-1) / 3;
if (all > 0)
{
life = year - 3;
for (int i = 4; i < year+1; i++)
{
life += NumNiu2(i - 3);
}
}
return life;
}

  回复  引用    
#37楼2008-02-02 13:28 | 白杨[未注册用户]
算法是不是有问题?
我怎么算出来 20年过后,总共有345头牛.

  回复  引用  查看    
#38楼[楼主]2008-02-02 16:25 | jillzhang      
@白杨
20年是872

  回复  引用  查看    
#39楼2008-03-18 11:40 | 一岩      
呵呵,我和#42楼算得一样。
这是一个变形的Fibonacci数列。
首先,要分清楚第一年和1年后是不同的。第一年等于0年后,所以条件是4年后即第五年生一只小牛。
注意,这个条件理解不一样可是会得出不同的结果的。
设n年后,牛共有S(n)头则可以推出:S(n)=S(n-1)+S(n-4)。
详细的推导过程可以看看的我的blog,欢迎指教

递归和递推算法:
程序实现(递归算法):
//y指y年后小牛个数
public static int getCount(int y)
{
if (y < 4)
{
return 1;
}
else
{
return getCount(y - 1) + getCount(y - 4);
}
}

递推算法:
//递推算法,y指y年后小牛个数
public static int getCountEasy(int y)
{
int[] a = new int[5] { 1, 1, 1, 1,0 };
if (y < 4)
{
return 1;
}
else
{
for (int i = 4; i < y+1; i++)
{
a[4] = a[3] + a[0];
a[0] = a[1];
a[1] = a[2];
a[2] = a[3];
a[3] = a[4];
}
return a[4];
}
}

  回复  引用  查看    
#40楼2008-06-03 17:37 | 姜敏      
本人不太应用算法,所以对算法的题都不太会用,学习了。
人老了,脑袋不好用了,偶尔用算法来练练脑子,可以防止早衰。呵呵
有同感啊。

  回复  引用    
#41楼2009-03-16 11:44 | 请不要误导读者[未注册用户]
算法是错的,
1).楼主请手动算下前10年数据,再和程序核对下
2).4年后<>第四年,所以理解错误

  回复  引用    
#42楼2009-03-16 13:15 | 请不要误导读者[未注册用户]
很显然,求N年后的牛的数量F(N)
等于N-1年后的牛的数量+在N年后新出生的牛的数量
即F(N)=F(N-1)+在N年后新出生的牛的数量
根据题意可知,N年后新出生的牛的数量也即在N年后有生育能力的牛的数量,
N年后有生育能力的牛肯定是4年前拥有的牛的总数量,即F(N-4)

得出关系式:F(N)=F(N-1)+F(N-4);

结论:楼主算法错误.




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 887286




相关文章:

相关链接: