Ø 要将一张100元的大钞票,换成等值的10元、5元、2元、1元一张的小钞票,每次换成40张小钞票,每种至少1张。如,有一种换法:
Ø 10元: 1 张
Ø 5元: 5 张
Ø 2元: 31 张
Ø 1元: 3 张
Ø问:一共有多少种换法。
数学模型:
View Code
View Code
View Code
View Code
Ø10元: a 张 (不超过10张)
Ø 5元: b 张 (不超过20张)
Ø 2元: c 张 (不超过50张)
Ø 1元: d 张 (不超过100张)
Ø不定方程:
Ø10*a+5*b+2*c+d=100
Øa+b+c+d=40
Øa>=1;b>=1;c>=1;d>=1
Ø方程有多少组正整数解?
方法1:
枚举abcd
#include<cstdio> int main(){ int s=0,a,b,c,d; for(a=1;a<=10;a++) for(b=1;b<=20;b++) for(c=1;c<=50;c++) for(d=1;d<=100;d++) if(a+b+c+d==40 && 10*a+5*b+2*c+d==100){ s=s+1; printf("%d : %d %d %d %d\n",s,a,b,c,d); } return 0; }
思考如何减少一层循环
方法2:
#include<cstdio> int main(){ int s=0,a,b,c,d; for(a=1;a<=10;a++) for(b=1;b<=20;b++) for(c=1;c<=40;c++){ d=40-(a+b+c); if(d>0&&10*a+5*b+2*c+d==100){ s=s+1; printf("%d : %d %d %d %d\n",s,a,b,c,d); } } return 0; }
还能再减少一层循环吗?
方法3:
Ø根据不定方程:
Ø10*a+5*b+2*c+d=100
Øa+b+c+d=40
Ø可得:
c=60-(9*a+4*b);
d=8*a+3*b-20;
这也只枚举a b即可。
#include<cstdio> int main(){ int s=0,a,b,c,d; for(a=1;a<=10;a++) for(b=1;b<=20;b++){ c=60-(9*a+4*b); d=8*a+3*b-20; if(c>0&&d>0){ s=s+1; printf("%d : %d %d %d %d\n",s,a,b,c,d); } } return 0; }
还可以继续优化吗?
方法4:
从枚举的范围进行优化
#include<cstdio> int main(){ int s=0,a,b,c,d; for(a=1;a<=7;a++) for(b=1;b<=17;b++){ c=60-(9*a+4*b); d=8*a+3*b-20; if(c>0&&d>0){ s=s+1; printf("%d : %d %d %d %d\n",s,a,b,c,d); } } return 0; }
结论:即使采用暴力枚举,也要认真分析问题。
常用的枚举优化措施:
(1)减少枚举层数;
(2)减少每一层的循环次数