代码改变世界

由简单小问题引发的思考和推理

2017-07-19 17:54  tlnshuju  阅读(210)  评论(0编辑  收藏  举报

事情是这种,昨天。有个小伙伴在群里发了个题目,让大家回答。题目本身是非常easy的,例如以下:

財迷有多少钱?

有一个財迷总想使自己的钱成倍增长。一天他在一座桥上碰见了一个老人,老人说:”你仅仅要走过这座桥再回来,你身上的钱就会添加一倍,但你每走一个来回要给我32个铜板。

“財迷认为合算。就允许了。他走过桥又走回来,身上的钱果然添加了一倍。他高兴地给了老人32个铜板。

这样走完第五个来回。財迷身上最后的32个铜板都给了老人,一个也没剩。

財迷身上原来有多少个铜板?

如何,题目本身简单吧?没错!大家第一感觉就是逆推,而且非常快就能逆推出答案:

第5次走完以后 0 走之前(0 + 32 )/2 = 16

第4次走完以后 16 走之前(16 + 32 )/2 = 24

第3次走完以后 24 走之前(24 + 32 )/2 = 28

第2次走完以后 28 走之前(28 + 32 )/2 = 30

第1次走完以后 30 走之前(30 + 32 )/2 = 31

这样的方式是一眼就能得出的方法,写成程序也非常easy:

int f(int x) //输入走之后有多少钱计算走之前有多少钱
{
return (x + 32) / 2;
}
int main()
{
int x = 0;
int count_max = 5;
for(int i = 0;i < count_max;i++)
{
x = f(x);
}
cout << "原来有  " << x << " 个铜板" << endl;
system("pause"):
return 0;
}

可是。慢着,这边出现了循环....并且循环里面仅仅是一个式子。那么我们能不能给他抽象成一个通项公式呢?

是能够的!

我们将次数抽象出来,n次以后用完铜板,那么

n == 1 :

a0 * 2 - 32 = 0     //a0 代表进入第1次时候的初始铜板

a0 = 32 / 2

n == 2 :

a1 * 2 - 32 = 0  

a0 * 2 - 32 = a1

结合上面两个式子 : (a0 * 2 - 32) * 2 - 32 = 0   =>  a0 = 32/2 + 32/4

n == 3 :

a2 * 2 - 32 = 0  

a1 * 2 - 32 = a2

a0 * 2 - 32 = a1

结合上面三个式子 : ((a0 * 2 - 32) * 2 - 32 ) * 2 - 32 = 0   =>  a0 = 32/2 + 32/4 + 32/8

...

如今 上面似乎有了规律:

若n次以后用完铜板

则 a0 = 32/(2^1)+ 32/(2^2) + 32/(2^3) ... 32/(2^n)

进一步化简为 

a0 = 32*(1/(2^1)+ 1/(2^2) + 1/(2^3) ... 1/(2^n))

进一步化简为 

a0 = 32*( (2^(n-1) +2^(n-2) + ... + 2^(n-n)) / 2^n )

进一步化简为 

a0 = 32*( 2^n - 1/ 2^n )

嘿嘿,这样就出来了一个简单的通项公式能够非常方便的求出初始有多少钱了!再把每次要付的钱设置为x 则为:

a0 = x*( 2^n - 1/ 2^n ) // a0为初始有多少铜板,x为每次付的钱, n为多少次以后用光全部钱


详细写成代码例如以下:

int f(int n, int x)
{
return x*((pow(2,n) - 1)/pow(2,n));
}
int main()
{
int x = 0;
int count_max = 5;
int money = 32;
x = f(count_max, money);
cout << "原来有  " << x << " 个铜板" << endl;
system("pause"):
return 0;
}

执行结果例如以下: