Ø      要将一张100元的大钞票,换成等值的10元、5元、2元、1元一张的小钞票,每次换成40张小钞票,每种至少1张。如,有一种换法:
Ø    10元:   1
Ø      5元:   5
Ø      2元:   31
Ø      1元:   3
Ø问:一共有多少种换法。
 
数学模型:
Ø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;
}
View Code

思考如何减少一层循环

方法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;
}
View Code
还能再减少一层循环吗?
方法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;
}
View Code
还可以继续优化吗?
方法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;
}
View Code
结论即使采用暴力枚举,也要认真分析问题。
 
常用的枚举优化措施
1)减少枚举层数;
2)减少每一层的循环次数