韩信点兵问题
来源:互联网 发布:php 发送模板消息代码 编辑:程序博客网 时间:2024/05/16 06:30
韩信点兵是一个有趣的猜数游戏。如果你随便拿一把蚕豆(数目约在100粒左右),先3粒3粒地数,直到不满3粒时,把余数记下来;第二次再5粒5粒地数,最后把余数记下来;第三次是7粒一数,把余数记下来。然后根据每次的余数,就可以知道你原来拿了多少粒蚕豆了。不信的话,你还可以试验一下。例如,假如3粒一数余1粒,5粒一数余2粒,7粒一数余2粒,那么,原有蚕豆有多少粒呢?
这类题目看起来是很难计算的,可是我国古时候却流传着一种算法,名称也很多,宋朝周密叫它“鬼谷算”,又名“隔墙算”;杨辉叫它“剪管术”;而比较通行的名称是“韩信点兵”。最初记述这类算法的是一本名叫《孙子算经》的书,后来在宋朝经过数学家秦九韶的推广,又发现了一种算法,叫做“大衍求一术”。这在数学史上是极有名的问题,外国人一般把它称为“中国剩余定理”。至于它的算法,在《孙子算经》上就已经有了说明,而且后来还流传着这么一道歌诀:
三人同行七十稀,
五树梅花廿一枝,
七子团圆正半月,
除百零五便得知。
这就是韩信点兵的计算方法,它的意思是:凡是用3个一数剩下的余数,将它用70去乘(因为70是5与7的倍数,而又是以3去除余1的数);5个一数剩下的余数,将它用21去乘(因为21是3与7的倍数,又是以5去除余1的数);7个一数剩下的余数,将它用15去乘(因为15是3与5的倍数,又是以7去除余1的数),将这些数加起来,若超过105,就减掉105,如果剩下来的数目还是比105大,就再减去105,直到得数比105小为止。这样,所得的数就是原来的数了。根据这个道理,你可以很容易地把前面的五个题目列成算式:
1×70+2×21+2×15-105
=142-105
=37
因此,你可以知道,原来这一堆蚕豆有37粒。
证明:
同理得证,sm满足条件2和条件3。因此sm是满足条件的一个数。
又因为如果有一个数x是a1,a2,a3的最小公倍数,则sm+k*x也是满足条件的一个数。由此可知,在(0~x)的范围内,有一个数是满足条件的。得证。
这类题目看起来是很难计算的,可是我国古时候却流传着一种算法,名称也很多,宋朝周密叫它“鬼谷算”,又名“隔墙算”;杨辉叫它“剪管术”;而比较通行的名称是“韩信点兵”。最初记述这类算法的是一本名叫《孙子算经》的书,后来在宋朝经过数学家秦九韶的推广,又发现了一种算法,叫做“大衍求一术”。这在数学史上是极有名的问题,外国人一般把它称为“中国剩余定理”。至于它的算法,在《孙子算经》上就已经有了说明,而且后来还流传着这么一道歌诀:
三人同行七十稀,
五树梅花廿一枝,
七子团圆正半月,
除百零五便得知。
这就是韩信点兵的计算方法,它的意思是:凡是用3个一数剩下的余数,将它用70去乘(因为70是5与7的倍数,而又是以3去除余1的数);5个一数剩下的余数,将它用21去乘(因为21是3与7的倍数,又是以5去除余1的数);7个一数剩下的余数,将它用15去乘(因为15是3与5的倍数,又是以7去除余1的数),将这些数加起来,若超过105,就减掉105,如果剩下来的数目还是比105大,就再减去105,直到得数比105小为止。这样,所得的数就是原来的数了。根据这个道理,你可以很容易地把前面的五个题目列成算式:
1×70+2×21+2×15-105
=142-105
=37
因此,你可以知道,原来这一堆蚕豆有37粒。
证明:
设三次数的数目分别为a1,a2,a3(3,5,7),三次的余数分别为b1,b2,b3(1,2,2);定义m为一魔法数,m的求法如下:
m是a,b,c的魔法数,则m mod a = 1,m mod b = 0, m mod c = 0;即m是b和c的公倍数,而且除以a的余数是1。由此我们可以求出m1,m2,m3。设sm是各个余数与mi的乘积的和。由此可得:
sm mod a1 = (m1*b1+m2*b2 + m3*b3 ) mod a1
同理得证,sm满足条件2和条件3。因此sm是满足条件的一个数。
又因为如果有一个数x是a1,a2,a3的最小公倍数,则sm+k*x也是满足条件的一个数。由此可知,在(0~x)的范围内,有一个数是满足条件的。得证。
算法如下:
#include "stdafx.h"int gcd(int a,int b){ while ( b != 0 ) { int temp = b; b = a % b; a = temp; } return a;}int mgcd(int a,int b){ return (a*b)/gcd(a,b);}struct node_t{ int a; int b;};int getminm(int a,int b,int c){ int m ; int r; r = m = mgcd(b,c); while ( r%a != 1) r += m; return r;}int getNum(node_t *pnode){ int m1,m2,m3,x; int sm; m1 = getminm(pnode[0].a,pnode[1].a,pnode[2].a); m2 = getminm(pnode[1].a,pnode[0].a,pnode[2].a); m3 = getminm(pnode[2].a,pnode[0].a,pnode[1].a); x = mgcd(pnode[0].a,pnode[1].a); x = mgcd(pnode[2].a,x); sm = pnode[0].b * m1 + pnode[1].b *m2 + pnode[2].b * m3; return sm%x;}int main(){ node_t node[3]; node[0].a = 3; node[0].b = 1; node[1].a = 5; node[1].b = 2; node[2].a = 11; node[2].b = 3; printf("蚕豆数:%d\n",getNum(node)); return 0;}
0 0
- 韩信点兵问题
- 韩信点兵问题
- 韩信点兵问题
- 韩信点兵问题
- 韩信点兵问题
- 韩信点兵问题
- 韩信点兵问题
- 韩信点兵问题------凌风
- 谈韩信点兵问题
- 韩信点兵问题算法
- C语言 韩信点兵问题
- 韩信点兵的问题求解方法
- 韩信点兵问题的神解法
- 程序设计入门3 韩信点兵问题
- //韩信点兵
- 韩信点兵
- 韩信点兵
- 韩信点兵
- 【算法】简单选择排序C语言实现
- Linux常用命令及目录
- FZU - 2155 - 盟国 (带删除的并查集~~)
- 认识Verilog Hdl语言
- HDOJ 题目1532 Drainage Ditches(最大流)
- 韩信点兵问题
- unity3d自动生成2D动画
- MongoDB创建表步骤,Mongo常用的数据库操作命令,查询,添加,更新,删除_MongoDB 性能监测
- Excel工作表标题(A,B,......DC)
- JSP中的basepath的使用说明
- 一个小时内学习SQLite数据库
- mongoDB2.6,java使用详解
- ShellCode的调试方法和常见问题的解决方法
- oracle中PLSQL Developer出现错误总结!