今天小孩参加一个“新初一”数学思维挑战赛活动, 反馈的一道难题,为了得到答案,于是想到用C++编程来计算,题意大至如下:
题意:
一个数字和为10的多位数(至少三位),数字取自1、2、5、6,且数字可以不全用,也可以重复用。那么这样的多位数共有多少个?
思路1:动态规划DP
1)定义一个数组 dp[i][j]
,其中 i
表示当前考虑的位数(从最低位开始,至少为3),j
表示当前已选择的数字之和。
2)初始化 dp[1][k]
(其中 k
为1, 2, 5, 6)为1,表示只有一位数时,有1个数字的和为 k
。
3)对于 i > 1
的情况,我们可以从 dp[i-1][j-k]
转移过来,其中 k
为当前可以选择的数字(1, 2, 5, 6),且 j-k
非负。即,如果我们在前 i-1
位得到了和为 j-k
的多位数,那么我们可以在最后一位加上数字 k
,从而得到和为 j
的 i
位数。
4)最后,我们需要的答案就是 dp[3][10] + dp[4][10] + dp[5][10] + ...
,即从3位数开始,所有和为10的多位数的数量之和。
源代码:
#include <iostream>
using namespace std;
int main() {
//初始化dp[i][j]数组,i表示当前考虑的位数,j表示当前已选择的数字之和
int dp[11][11]={};
// 初始化一位数的情况
dp[1][1] = dp[1][2] = dp[1][5] = dp[1][6] = 1;
// 动态规划过程,从第2位开始计算
for (int i = 2; i <= 10; ++i) { // 最多考虑10位数
for (int j = 1; j <= 10; ++j) { // 数字和的范围
for (int k : {1, 2, 5, 6}) { // 可以选择的数字
if (j >= k) // 保证j-k非负
dp[i][j] += dp[i-1][j-k];
}
}
}
// 计算结果,从3位数开始累加和为10的数的数量
int result = 0;
for (int i = 3; i <= 10; ++i) {
result += dp[i][10];
}
cout << "这样的多位数共有 " << result << " 个。" << endl;
return 0;
}
思路2:递归法
-
递归函数
countNumbers
,接受当前累加的和currentSum
、当前数字的位数length
、已经构建的数字的前缀prefix
以及可用的数字集合digits
。 -
函数首先检查是否达到了终止条件:如果当前和等于10且位数至少为3,则找到了一个解,并返回1。如果当前和超过10或位数超过了10位数,则函数返回0,表示不再继续搜索。
-
在函数主体中,遍历所有可用的数字,并尝试将它们添加到当前前缀中。对于每个数字,递归调用
countNumbers
函数,并更新currentSum
和length
。递归调用返回的结果累加到count
变量中。 -
最后,输出总的数量。
源代码:
#include <iostream>
#include <vector>
using namespace std;
// 递归函数,用于计算数字和为10的多位数的数量,currentSum: 当前累加的和
// length: 当前数字的位数,prefix: 已经构建的数字的前缀(作为字符串处理)
int countNumbers(int currentSum, int length, const string& prefix, const vector<int>& digits) {
// 终止条件:如果当前和等于10且长度至少为3,则找到一个解
if (currentSum == 10 && length >= 3) {
return 1; // 增加一个解
}
// 终止条件:如果当前和已经超过10,或者长度超过10位
if (currentSum > 10 || length > 10) {
return 0; // 不再增加解
}
int count = 0;
// 遍历所有可能的数字
for (int digit : digits) {
// 尝试添加当前数字到前缀中,并递归调用函数
string newPrefix = prefix + to_string(digit);
count += countNumbers(currentSum + digit, length + 1, newPrefix, digits);
}
return count;
}
int main() {
vector<int> digits = {1, 2, 5, 6}; // 可用的数字
int totalCount = countNumbers(0, 0, "", digits); // 从0开始
cout << "这样的多位数共有 " << totalCount << " 个。" << endl;
return 0;
}
运行结果:
这样的多位数共有 147 个。