鸡兔同笼问题、百鸡问题、辗转相除法求最大公约数
一、鸡兔同笼
鸡和兔子35只,腿一共有94条,求出鸡和兔子的数量各是多少?(鸡的数目是23,兔子的数目是12)
$n = 0;
for($ i=1;$i<35;$i++){
$n ++; //n=34;
$ j=35-i;
if(i*2+j*4==94){
printf("鸡的数目是%d只, 兔子的数目是%d只",$i,$j);
}
}
此时,循环进行了34次。但是,有些循环是无意义的,因为得到了结果,循环还在继续往下执行。我们知道:两个未知数,两个方程,其方程组的解唯一!那么我们可以让流程控制的if语句在得到结果以后,终止循环!
改进如下:
$n = 0;
for($ i=1;$i<35;$i++){
$n ++; //n=23;
$ j=35-i;
if(i*2+j*4==94){
printf("鸡的数目是%d只, 兔子的数目是%d只",$i,$j);
break;
}
}
此时,循环只需要进行23次即可。再有,在确定循环变量的时候,分析:兔有四条腿,而鸡只有两只脚,兔子数明显比鸡的个数所得到的腿数更有效!(有点绕,大家不理解的看下面代码~)
终极版改进如下:
$n = 0;
for($ i=1;$i<35;$i++){
$n ++; //n=12;
$ j=35-i;
if(i*4+j*2==94){
printf("鸡的数目是%d只, 兔子的数目是%d只",$j,$i);
break;
}
}
最后,我们获得结果只需要循环12次!比起最开始的34次,节省了22次不必要的循环!可能大家觉得没什么,如果是循环一万次一百万次呢,不必要的循环多了,消耗的资源也就多了,获得最终结果的速度也慢了。
二、百鸡问题
张丘建在《算经》中提出了“百鸡问题”:鸡公一值钱五,鸡母一值钱三,鸡雏三值钱一,百钱买百鸡,问鸡公、母、雏各几何?
先给大家罗列出结果:
公鸡有0只,母鸡有25只,小鸡有75只
公鸡有4只,母鸡有18只,小鸡有78只
公鸡有8只,母鸡有11只,小鸡有81只
公鸡有12只,母鸡有4只,小鸡有84只
同样的,我们让计算机帮我们计算,代码如下:
$n = 0;
for($cocks = 0;$cocks <= 20;$cocks ++){
for($hens = 0;$hens <= 33;$hens ++){
$n++; //n = 714;
$chicks = 100 - $cocks - $hens;
if(5*$cocks + 3*$hens + $chicks/3 == 100) {
printf("公鸡有%d只,母鸡有%d只,小鸡有%d只<br />",$cocks,$hens,$chicks);
}
}
}
要想得到结果,计算机需要循环21*34=714次。接下来怎么优化呢?假设公鸡数为x,母鸡数为y,小鸡数为z。我们先把z消去,得7x+4y = 100,x = (100-4y)/7,那么x最大只能得到14,节省了(20-14)*34=204次循环!另外,我们可以发现,如果少买7只母鸡,就可多买4只公鸡和3只小鸡!我们是不是可以再得到最大的母鸡数,然后递减7,以及公鸡数+4、小鸡数+3来获取最终结果呢?
代码如下:
$n = 0;
for($cocks = 0;$cocks <= 14;$cocks ++){
for($hens = 33;$hens >=0;$hens --){
$n++;
$chicks = 100 - $cocks - $hens;
if(5*$cocks + 3*$hens + $chicks/3 == 100) {
printf("公鸡有%d只,母鸡有%d只,小鸡有%d只<br />",$cocks,$hens,$chicks);
break; //得到最大的母鸡数;
}
}
if(printf()){
break; //如果printf()有返回值,即内层循环得出了结果,那么就终止!;
}
}
不知道为什么浏览器报错了。。。程序出现问题,待改进。
1,break指的是从当前的中断语句开始算起,往外层循环中断的层数,默认是1。要想中断两层循环,break 2即可;
2,查手册,得printf为字符串函数,原型为:int printf ( string $format
[, mixed $args
[, mixed $...
]] ),它有一个返回值,返回值为输出字符串的长度。浏览器报错为:Warning: printf() expects at least 1 parameter,即printf()期待至少一个参数在里面,而我没有写入参数;
3,得到有结果就终止的方法也许不那么可靠,毕竟循环只进行了那么几次,我们不知道后续的执行情况如何。
为了减少循环次数,优化代码,可以减少一层循环。定义的公鸡数$cocks从0开始,每次加1,换句话说,已经保证了$cocks为正整数!把小鸡数$chicks消去得到的等式,
7x+4y = 100,y=(100-7x)/4,y也应该是一个正整数。若x、y确定了,z的值随之确定。只需要将x从0~14代入,y的表达式也同时为正整数即可。
使用一层循环来求百鸡问题,代码如下:
$n = 0;
for($cocks = 0;$cocks<=14;$cocks++){
$n++; //n = 15;
$hens = (100-7*$cocks)/4;
if(is_int($hens)){
printf("公鸡有%d只,母鸡有%d只,小鸡有%d只<br />",$cocks,$hens,100-$cocks-$hens);
}
}
使用一层循环,只需要循环15次就能得到最终的结果。比起使用两层循环的714次,节省了699次。由此可得,我们在实际工作中,为了使代码更高效,尽可能地避免使用太多层的循环。
三、辗转相除法求最大公约数
$num1 = $_GET['n1'];
$num2 = $_GET['n2'];
$num = $num1;
$div = $num2;
//求余数,开始循环体
do {
$mod = $num % $div;
// 刚才的除数就变成了被除数
$num = $div;
// 刚才的余数就变成了除数
$div = $mod;
}while($mod != 0);
echo "最大公约数为:",$num;