代码意识流——花朵数问题(三)

本文前一部分的链接
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位数情况测试,输出正确

到此,穷举部分基本完成。

posted @ 2011-06-01 11:11  键盘农夫  阅读(2044)  评论(15编辑  收藏  举报