題目: 寫C++程式碼設計遞迴函數產生3個數字不同且加總等於M的所有3位數，M是輸入的整數，百位數必須非零。
答案: 若想產生3個數字不同且加總等於M的所有3位數，且百位數必須非0，則這三個數字必皆為個位數。  => 必須注意最大的M是24 = 9 + 8 + 7，而最小的M是3 = 2 + 1 + 0。  總共填3次，第一次填1~limit，第二次填0~limit(若第一次填的數字在內，需跳過其)，第三次只填一個(M減掉前兩次填的數字)。  limit是填入後不會使後面的數字填不了的最大數字，如M = 9時，limit = 8，因為8後面尚可填1&0；或是如M = 9且第一個數是7時，limit = 2，因為7、2後面尚可填0。  以下是程式碼：  #include <iostream> #include <vector> #include <algorithm> using namespace std ;  int permuCount = 0 ;      // to record the total amounts of permutation in a case. vector<int> empty ;       // an empty array.  bool isRecur = false ;     // indicates if the recurive function is on its first time or recursing. void permuPrinter( vector<int> arr ) ; void allThreeNumSumUpAsM( vector<int>& arr, vector<int>& recur, int target, int currentItem ) ;  int main() {     int m = 0 ;      vector<int> arr ;              cout <<  \nPlease insert a positive number M:   ;     for( ; m < 1 ; ) {           cin >> m  ;         if( m < 1 || cin.fail() ) {               cout <<  Invalid input, please try again.\n  ;               cin.clear() ;        // if cin failed, reset its flag ( fail: invalid type.  e.g. cin 'a' to an int variable).               cin.sync() ;         // and clear its temp.           ( without this, next cin will change its flag to fail and stop cin immediately.)         } // end of if                          } // end of for                      cout <<  \n\nResult: \n  ;                      // make arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }     arr.clear() ;     for( int first = 0 ; first <= 9 ; first++ ) {         arr.push_back(first) ;     } // end of for                      empty.resize(3) ;            // Rest empty to a n items array full of 0.     permuCount = 0 ;     allThreeNumSumUpAsM( arr, empty, m, 0 ) ; } // main()   void allThreeNumSumUpAsM( vector<int>& arr, vector<int>& recur, int target, int currentItem ) {     vector< vector<int> > result( 9, vector<int>(3) ) ;     int idxArr = 0 ;     int idx1 = 0 ;     int idx2 = 0 ;     int limit = 9 ;     int addTimes = 9 ;          // if target is less than 3 or larger than 24, for example = 2, then we wouldn't be able to find the 3 numbers.      if( target >= 3 && target <= 24 ) {         if( currentItem == 0 ) {             idxArr = 1 ; // result can't be something like  031  or  049 , so possible number for first are 1~9.             while( target - limit <= 0 ) { // e.g. if m = 9, then first number's max is 8 for  810  and  801 .                 limit = limit - 1 ;                } // end of while                         addTimes = limit - idxArr + 1 ; // first time, possible numbers are from 1 to limit.         } // end of if              else if( currentItem == 1 ) { // e.g. if m = 9 and first number = 8, then second number's max is 1 for  810  and  801 .             while( target - recur[0] - limit < 0 ) {                 limit = limit - 1 ;                 } // end of while                             addTimes = limit - idxArr + 1 ; // second time, possible numbers are from 0 to limit, except the first number.             if( recur[0] <= limit && recur[0] >= idxArr ) {                 addTimes = addTimes - 1 ;             } // end of if                      } // end of else if                  else if( currentItem == 2 ) { // third or the last number will be target - recur[0] - recur[1].             idxArr = target - recur[0] - recur[1] ;             limit = target - recur[0] - recur[1] ;             if( limit > 9 ) {                 currentItem = 100 ; // if limit is bigger than 9, then this combination is impossible.             } // end of if                          addTimes = 1 ; // only 1 possible number for third time.         } // end of else if                               for( idx1 = 0 ; idx1 < addTimes && currentItem < 3 ; idx1++ ) {             for( idx2 = 0 ; idx2 < 3 && isRecur ; idx2++ ) {                 result[idx1].at(idx2) = recur[idx2] ;             } // end of for                          for( bool isAdded = false ; idxArr <= limit && !isAdded ; idxArr++ ) {                 if( find( result[idx1].begin(), result[idx1].end(), arr[idxArr] ) == result[idx1].end() ) {                     result[idx1].at(currentItem) = arr[idxArr] ;                     isAdded = true ;                 } // end of if                              } // end of for                      } // end of for                  if( currentItem == 3 ) {             for( idx2 = 0 ; idx2 < 3 && isRecur ; idx2++ ) {                 result[0].at(idx2) = recur[idx2] ;             } // end of for                          if( result[0][0] + result[0][1] + result[0][2] == target ) {                 permuPrinter( result[0] ) ;             } // end of if                      } // end of if              else if( currentItem < 3 ) {                 isRecur = true ;                 for( idx1 = 0 ; idx1 < addTimes ; idx1++ ) {                 allThreeNumSumUpAsM( arr, result[idx1], target, currentItem + 1 ) ;             } // end of for                      } // end of else if          } // end of if          else {         cout <<  Unable to find 3 number which sum up as   << target <<  \n  ;     } // end of else          } // allThreeNumSumUpAsM()  void permuPrinter( vector<int> arr ) {     permuCount = permuCount + 1 ;     cout <<  【  << permuCount <<  】   ;     for( int idx = 0 ; idx < 3 ; idx++ ) {             cout << arr[idx] <<     ;     } // end of for        cout <<  \n  ; } // permuPriter()
評論: 程式碼可以正常執行，敘述邏輯的表達清楚。  內部有二個while迴圈可否簡化成if敘述直接計算？  例如這個：  while( target - recur[0] - limit < 0 ) {                 limit = limit - 1 ;                 } // end of while 延伸閱讀：  維基百科: https://en.wikipedia.org/wiki/Subset_sum_problem  學術論文：https://ieeexplore.ieee.org/document/9504889