使用“數制”解組合策略問題
問題:
序列123...N,N介于3和9之间,在其中加入+、-或者空格,使其和为0。
如123456,1-2 3-4 5+6 7,等价于1-23-45+67=0。
解答:
網上找來的代碼。
1 //序列123...N,N介于3和9之间,在其中加入+、-或者空格,使其和为0, 2 //如123456 1-2 3-4 5+6 7 等价于1-23-45+67=0。请问,如何获得所有组合?使用递归和非递归。 3 //非递归算法 4 #include <iostream> 5 #include <cmath> 6 using namespace std; 7 8 void func (char* str); 9 void calc (char* result); 10 11 int main() 12 { 13 char str[] = "123456789"; 14 func(str); 15 return 0; 16 } 17 18 void func(char* str) 19 { 20 //初始化输出数组 21 int len = strlen(str); 22 char* result = new char[len*2]; 23 for (int i = 0; i < len; i++) { 24 result[i*2] = str[i]; 25 } 26 result[len*2-1] = '\0'; 27 28 //模拟3进制的运算 29 char key[3] = {' ', '+', '-'}; 30 int n = pow(3.0, len - 1); 31 for (int i = 0; i < n; i++) { 32 //把i转换成3进制,计算每一位,转换成字符,填入字符串相应位置 33 int pos = len * 2 - 3; //个位数填入位置 34 int temp = i, mod; 35 do { 36 mod = temp % 3; 37 temp /= 3; 38 result[pos] = key[mod]; 39 pos -= 2; 40 } while (temp > 0); 41 //高位补0 42 while (pos > 0) { 43 result[pos] = key[0]; 44 pos -= 2; 45 } 46 calc(result); //计算结果并输出 47 } 48 49 delete[] result; 50 } 51 52 void calc(char* result) 53 { 54 int sum = 0, sign = 1, i = 0; 55 int temp = 0; 56 while (result[i] != '\0') { 57 if (result[i] == ' ') { 58 temp *= 10; 59 } 60 else if(result[i] == '+' || result[i] == '-') { 61 sign = (result[i] == '+') ? 1 : -1; 62 sum += temp; 63 temp = 0; 64 } 65 else { 66 temp += sign * (result[i] - '0'); 67 } 68 i++; 69 } 70 sum += temp; 71 if (sum == 0) { 72 cout << result << endl; 73 } 74 }
説明:
序列123...N,在數字之間插入“+”、“-”或“ ”,N 個數字之間有 N-1 個間隔,所以一共有 3^(N-1) 种方法。
利用“數制”可以輕鬆產生這些組合排列。
二進制數表示法,就是用0\1兩個數的組合排列,一個 byte 有 8 個 bits, 就有 2^8 個組合排列數,因此可以表示 [0,255] 這些數。
十進制數就由十個符號 “0123456789” 組合排列得到。
現在反向思考,我們需要是所有的組合排列,用一個數字就可以表示一種組合排列。
所以可以用 [0,3^(N-1)] 這些數表示所有 N 位的三進制數。
就說這些,我只能說得這麽清楚了。