大数
// 先将十个数字的21次方手动计算出来,存入初始数组中 // 枚举各个数字所有可能情况 //可能的情况:每个数字个数之和为不超过21且加和正好为21 // 对于每一种情况计算加和 // 判断: // 所得加和是否为21位数 // 各个数字个数是否对应相等 // 对最终的答案数组按从小到大排序,然后顺序输出 /* * 总结: * 1.调试技巧:分块测试,逐块测试,黑盒测试(只能保证大部分对,不能保证个别细节对,适用于没有什么特殊点的程序的测试) * 2.写程序首先要思路清晰,如本次就写出来描述了,但还有点心急,细节没有仔细考虑周全就写,这样会导致调试时间的耗费,得不偿失,要知道我写程序写了1小时,调试却花了4个小时 * 3.写程序能常规尽量常规,因为非常规更容易导致错误;写代码要表现出逻辑性,即使某些步骤可以省略,也要加上以体现其逻辑 */ #include <iostream> #include <algorithm> #include <conio.h> using namespace std; #define ANSWER_COUNT 100 int num[10][30] = { {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 9, 7, 1, 5, 2}, {11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 6, 0, 3, 5, 3, 2, 0, 3}, {13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 3, 9, 8, 0, 4, 6, 5, 1, 1, 1, 0, 4}, {15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5}, {17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 9, 3, 6, 9, 5, 0, 6, 4, 0, 3, 7, 7, 8, 5, 6}, {18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 8, 5, 4, 5, 8, 6, 4, 0, 8, 3, 2, 8, 4, 0, 0, 7}, {19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8}, // 0.不仔细:抄错 {21, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9, 4, 1, 8, 9, 8, 9, 1, 3, 1, 5, 1, 2, 3, 5, 9, 2, 0, 9} }; int ans[100][30]; int p[100]; int _count; void mul(int _num[], int cnt, int res[]) { int i; int tmp = 0; for (i = 29; i >= 29 - _num[0] + 1; i--) { tmp += cnt * _num[i]; // 4.此处的称号竟然写成了+,同下为 "心手不一的潜意识思维定势" res[i] = tmp % 10; tmp /= 10; } while (tmp > 0) { res[i--] = tmp % 10; tmp /= 10; } if (cnt == 0) // 6.[bug]注意!!! :只有0会缩减数位,所以0还是具有其特殊性,此处不能一概写成res[0] = 29 - i; res[0] = 1; else res[0] = 29 - i; } void add(int num1[], int num2[]) { int i; int tmp = 0; int n = max(num1[0], num2[0]); for (i = 29; i >= 29 - n + 1; i--) { tmp += num1[i] + num2[i]; num1[i] = tmp % 10; tmp /= 10; } while (tmp > 0) { num1[i] = tmp % 10; tmp /= 10; } num1[0] = 29 - i; } bool test(int res[], int arr[]) { int cnt[10] = { 0 }; for (int i = 29; i >= 29 - res[0] + 1; i--) { cnt[res[i]]++; } for (int i = 0; i < 10; i++) { if (cnt[i] != arr[i]) return false; } return true; } void dfs(int arr[], int cur) { if (cur >= 9) { // 1.此步忘掉了一个关键的条件:数组所有的和必须为21才行 int sum = 21; for (int i = 0; i < 9; i++) { // 3.此处竟然写成了i < 10, 应是减去9前面的,心理是这么想的,但写出又是另外一回事思维定势热惹得祸 sum -= arr[i]; } arr[9] = sum; int res[30] = {0}; res[0] = 1; // 5.为了避免意想不到的漏洞,这句还是要加上 int tmp[30] = {0}; for (int i = 0; i < 10; i++) { mul(num[i], arr[i], tmp); add(res, tmp); } if (res[0] == 21 && test(res, arr) == true) { for (int i = 0; i < 30; i++) { ans[_count][i] = res[i]; } _count++; // 2.低级错误,将此部分写到上面的循环里了 } return; } int tmp = 21; for (int i = 0; i < cur; i++) tmp -= arr[i]; int arr_cur = arr[cur]; for (int i = 0; i <= tmp; i++) { arr[cur] = i; dfs(arr, cur + 1); } arr[cur] = arr_cur; } int cmp(int num1[], int num2[]) { if (num1[0] != num2[0]) return num1[0] > num2[0] ? 1 : 0; int n = num1[0]; for (int j = 29 - n + 1; j <= 29; j++) { if (num1[j] != num2[j]) return num1[0] > num2[0] ? 1 : 0; } } void my_sort() { int k = 0; int tmp; int flag[ANSWER_COUNT] = { 0 }; for (int i = 0; i < _count; i++) { if (!flag[i]) { tmp = i; for (int j = 0; j < _count; j++) { if (j !=i && !flag[j] && cmp(ans[j], ans[i]) == 1) { tmp = j; } } p[k++] = tmp; flag[tmp] = 1; } } } int main() { int arr[10]; _count = 0; dfs(arr, 0); my_sort(); for (int i = 0; i < _count; i++) { int j = p[i]; for (int k = 29 - ans[j][0] + 1; k <= 29; k++) { cout << ans[j][k]; } cout << endl; } return 0; }