代码意识流——花朵数问题(三)
本文前一部分的链接
http://www.cnblogs.com/KBTiller/archive/2011/05/31/2064262.html
7.更直接了当的穷举方案
既然第二种方案在本质上无非是给出各位数字的各种组合,那么也许不如索性更直接一些。第3种方案虽然略有些抽象但却更加直接。
方案3.
for( 数字(JINZHI-1)的个数=0 ; 数字(JINZHI-1)的个数<=总位数 ; 数字(JINZHI-1)的个数++)
for( 数字(JINZHI-2)的个数=0 ;数字(JINZHI-2)的个数<=总位数-数字(JINZHI-1)的个数 ; 数字(JINZHI-2)的个数++ )
……
for( 数字1的个数=0 ; 数字1的个数<=总位数-前面各数字个数之和 ; 数字1的个数++)
{
//数字0的个数= 总位数-前面各数字个数之和
//<=>验算<=>记录结果
}
这种方案循环嵌套的深度比第二种方案要浅,对于数量巨大的计算更有优势。
8.测试方案可行性
对3进制5位数情况测试方案是否可行。
修改
/*2_穷举.c*/ #include "2_穷举.h" extern void qiongju( void ) { int n2; for(n2=0;n2<=WEISHU;n2++){ int n1; printf("%d个%d ",n2,JINZHI-1); for(n1=0;n1<=WEISHU-n2;n1++) { int n0; printf("%d个%d ",n1,JINZHI-2); { n0 = WEISHU - n2 - n1 ; printf("%d个%d",n0,0); putchar('\n'); //<=>验算<=>记录结果 } } } }
修改
/*0_问题.h*/ #ifndef WENTI_H #define WENTI_H #define CESHI //进行测试 //#define QIUJIE //求解21位问题 #ifdef CESHI //测试 #define JINZHI 3//10 //十进制 #define WEISHU 5//3 //3位花朵数 #define N WEISHU //幂次==位数 #endif //CESHI #ifdef QIUJIE //求解 #define JINZHI 10 //十进制 #define WEISHU 21 //位数 #define N WEISHU //幂次==位数 #endif //QIUJIE #endif // WENTI_H
修改
/*2_穷举.h*/ #ifndef QIONGJU_H #define QIONGJU_H #include "0_问题.h" //函数qiongju( )用到了JINZHI、WEISHU /**************************类型定义**************************/ /**************************函数原型**************************/ extern void qiongju( void ); #endif // QIONGJU_H
运行结果符合期待,表明方案可行。
9.把嵌套改成递归
循环嵌套只能描述固定层数的嵌套结构,所以前面的方案只能写出某特定进制的情况(3进制2层循环……10进制9层循环)。如果希望代码对不同进制的问题都成立,需要把循环的嵌套改成函数的递归,即用函数描述每一层循环及最内层的循环体部分的运算。
即使是只考虑十进制的情况,这样的修改也是必要的。因为循环嵌套的结构复杂、繁琐,不利于修改(后面应该还有许多内容需要添加)和维护。况且,写9层循环多少有些让人不寒而栗,至少对我来说是这样,不痛下决心是没勇气写9层循环嵌套的。
每一层循环(包括最内层的循环体)都需要两个参数确定:枚举的是哪个数字,这个数字的个数最多有几个(上限)。以第一层循环为例
for(n2=0;n2<=WEISHU;n2++){
printf("%d个%d ",n2,JINZHI-1);
……
}
需要"WEISHU"、"JINZHI-1"这两个参数。第二层循环和最内层的循环体同样需要这两个参数。
对于函数的递归调用来说,获得这些参数的的途径可能有三种:函数调用的实参,外部变量,局部static变量。最常用的是第一种,外部变量的办法通常是写不出手的,局部static变量的办法写起来要稍微困难一点。
修改后的qiongju()函数的定义为
/*2_穷举.c*/ #include "2_穷举.h" static void xunhuan(const int ,const int ) ; extern void qiongju( void ) { xunhuan( WEISHU , JINZHI-1 ) ; } static void xunhuan( const int gssx /*个数上限*/, const int sz /*关于哪个数字*/) { if( sz > 0 ){ int i; for( i = 0 ; i <= gssx ; i++ ){ printf("%d个%d " , i , sz ); xunhuan( gssx - i , sz - 1 ); } } else{ printf("%d个%d " , gssx , sz ); putchar('\n');//<=>验算<=>记录结果 } }
测试:
对3进制5位数情况测试,与原来结果一致
对10进制3位数情况测试,输出正确
到此,穷举部分基本完成。