1.题目
我国古代数学家张丘建在《算经》一书中曾提出著名的“百钱买百鸡”问题:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?
翻译过来,意思是公鸡一个五块钱,母鸡一个三块钱,小鸡三个一块钱,问公鸡、母鸡、小鸡各多少只?
2.枚举法思想解法
2.1 枚举法思路
- 枚举变量:公鸡,母鸡,小鸡对应了i,j,k
- 枚举范围:公鸡,母鸡,小鸡都是1-100次,对应了i,j,k分别循环一百次
- 枚举判断条件:
- 钱数=100:5公鸡+3母鸡+1/3小鸡=100 对应 5i+3j+k/3 == 100
- 总鸡数=00:公鸡+母鸡+小鸡=100 对应 i+j+k == 100
- 小鸡必须为整数:小鸡%3=0 对应 k%3 == 0
#include<iostream>
using namespace std;
int main()
{
int count = 0;
for(int i = 1 ; i <= 100 ; i++)
{
for(int j = 1 ; j <= 100 ; j++)
{
for(int k = 1 ; k <= 100 ; k++)
{
count++;
if(k%3 == 0 && 5*i+3*j+k/3 == 100 && i+j+k == 100){
cout<<"鸡翁"<<i<<"只,鸡母"<<j<<"只,鸡雏"<<k<<"%d只"<<endl;
}
}
}
}
cout<<"循环次数="<<count<<endl;
return 0;
}
看得出来总循环次数是1000000次
3.第一次优化:缩小枚举范围
- 因为一百块钱总共可以买20只公鸡,且母鸡和小鸡最少一只,因此公鸡的取值范围可以缩小为1-18也就是1≤i≤18
- 因为一百块钱最多可以买34只母鸡(33.33),且公鸡和小鸡最少一只,因此母鸡的取值范围为1≤j≤32
- 因为小鸡一元三只,所以这里无所缩小,公鸡和母鸡最少一只,因此小鸡的取值范围为1-98,也就是1≤k≤98
#include<iostream>
using namespace std;
int main()
{
int count = 0;
for(int i = 1 ; i <= 18 ; i++)
{
for(int j = 1 ; j <= 32 ; j++)
{
for(int k =1 ; k <= 98 ; k++ )
{
count++;
if(k%3 == 0 && 5*i+3*j+k/3 == 100 && i+j+k==100){
cout<<"鸡翁"<<i<<"只,鸡母"<<j<<"只,鸡雏"<<k<<"只"<<endl;
}
}
}
}
cout<<"循环次数="<<count<<endl;
return 0;
}
看得出来总循环次数是56448次
4.第二次优化:减少枚举变量
- 因为公鸡,母鸡和小鸡的总数是100,所当公鸡和母鸡确定的时候,小鸡就可以用总数减去公鸡,减去母鸡来表示也就是k=100-i-j;
#include<iostream>
using namespace std;
int main()
{
int count = 0;
for(int i = 1 ; i <= 18 ; i++)
{
for(int j = 1 ; j <= 32 ; j++)
{
count++;
int k = 100 - i - j;
if(k%3 == 0 && 5*i+3*j+k/3 == 100){
cout<<"鸡翁"<<i<<"只,鸡母"<<j<<"只,鸡雏"<<k<<"只"<<endl;
}
}
}
cout<<"循环次数="<<count<<endl;
return 0;
}
看得出来总循环的次数是576
5.第三次优化:进一步减少枚举变量
- 先来看三个枚举变量之间的关系
- i+j+k=100
- 5i+3j+k/3=100
利用上述二式,消去k得14i+8j=200–>7i+4j=100
j = (100-7i)/4
k = 100 - (100-7i)/4
- 从7i+4j=100可以推出j最小取1,则4j为4,7i最大为96,故i的取值范围为1-13
#include<iostream>
using namespace std;
int main()
{
int count = 0;
for(int i = 1 ; i <= 13 ; i++)
{
count++;
int j = (100-7*i)/4;
int k = 100 - j -i;
if( (100-7*i)%4 == 0 && k%3 == 0){
cout<<"鸡翁"<<i<<"只,鸡母"<<j<<"只,鸡雏"<<k<<"只"<<endl;
}
}
cout<<"循环次数="<<count<<endl;
return 0;
}
看得出来总循环次数减少到了13
大家可以看得出来枚举法的总体思路是比较简单的并不复杂,所以我们需要尽可能的去优化它。从最开始的1000000优化到最后的13次,可以看出优化的作用,更可以从中体会到算法的魅力!
4个cpp源文件下载:点击下载
其实没必要下载,自己从代码框中复制就可以了