题解:学而思编程 数字和为x的整数
【题目来源】
学而思编程:数字和为x的整数
【题目描述】
给定一个正整数 \(n\),请从小到大依次输出在 \(1∼n\) 之间(包含 \(1\) 和 \(n\))所有的整数中,各位数字和为 \(x\) 的整数,并统计其出现个数。
【输入】
一行,两个空格隔开正整数 \(n,x\)。
【输出】
若干行,每行一个整数,表示各位数字和为 \(x\) 的整数。
最后一行一个整数,表示各位数字和为 \(x\) 的整数出现的个数。
如果不存在各位数字和为 \(x\) 的整数,那么只需要输出 \(−1\)。
【输入样例】
1000 26
【输出样例】
899
989
998
3
【核心思想】
-
问题分析:给定正整数 \(n\) 和 \(x\),找出 \(1\) 到 \(n\) 中所有各位数字和等于 \(x\) 的整数,从小到大输出并统计个数。这是一个深度优先搜索 + 剪枝问题,关键在于按位数生成数字,并通过数字和与数值上限进行剪枝。
-
算法选择:
- DFS 按位生成:从最高位到最低位逐位确定数字,生成所有不超过 \(n\) 位数长度的数字
- 双重剪枝:当前数值超过 \(n\) 时剪枝;当前数字和超过 \(x\) 时剪枝
- 标记去重:用
vis数组标记已找到的数字,避免重复
-
关键步骤:
- 初始化:读取 \(n\) 和 \(x\),计算 \(n\) 的位数
len - DFS 搜索(
dfs(step)):- 计算当前已生成数字的数值
sum和各位数字之和res - 若
sum > n:剪枝返回 - 若
res > x:剪枝返回 - 若
step == len(已生成完整位数):- 若
res == x且!vis[sum]:找到符合条件的数字,cnt++,标记vis[sum] = true - 返回
- 若
- 遍历当前位 \(i\) 从 \(0\) 到 \(9\):
path[step] = idfs(step + 1)
- 计算当前已生成数字的数值
- 输出结果:
- 若
cnt == 0:输出 \(-1\) - 否则:输出所有符合条件的数字,最后输出
cnt
- 若
- 初始化:读取 \(n\) 和 \(x\),计算 \(n\) 的位数
-
时间/空间复杂度:
- 时间复杂度:\(O(10^{len})\),最坏情况遍历所有 \(len\) 位数,但剪枝大幅优化
- 空间复杂度:\(O(len)\),递归深度为
len
-
DFS 剪枝的核心思想:
- 按位生成:从高位到低位逐位确定,天然保证生成数字的递增顺序(配合输出时排序或按序存储)
- 数值上限剪枝:当前前缀已大于 \(n\) 时,后续任何填充都会超出范围,直接返回
- 数字和剪枝:当前数字和已超过 \(x\) 时,后续添加非负数字只会更大,不可能等于 \(x\),直接返回
- 位数控制:只生成
len位数字,避免短数字的重复生成(如 \(089\) 与 \(89\)) - 适用于"数位约束下的数字枚举"类问题,DFS 配合剪枝可高效搜索解空间
【算法标签】
DFS-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 10; // 定义最大数字长度
int n, x, len, cnt; // n: 上限数字,x: 目标数字和,len: n的位数,cnt: 符合条件的数字计数
int path[N]; // 记录当前生成的数字各位
int str[N]; // 存储符合条件的数字(实际未使用完整功能)
bool vis[2000005]; // 标记数字是否已被记录(去重)
// 深度优先搜索生成所有可能的数字
void dfs(int step) {
// 计算当前已生成的部分数字的值
int sum = 0;
for (int i = 0; i < step; i++) {
sum = sum * 10 + path[i];
}
// 剪枝:如果当前数字已超过上限n,停止搜索
if (sum > n) return;
// 计算当前数字各位之和
int res = 0;
for (int i = 0; i < step; i++) {
res += path[i];
}
// 剪枝:如果当前数字各位之和已超过x,停止搜索
if (res > x) return;
// 如果生成了完整位数的数字,检查是否满足条件
if (step == len) {
if (res == x && !vis[sum]) { // 数字和等于x且未被记录
cnt++;
str[cnt] = sum; // 存储符合条件的数字
vis[sum] = true; // 标记该数字已记录
}
return;
}
// 递归生成下一位数字(0-9)
for (int i = 0; i <= 9; i++) {
path[step] = i;
dfs(step + 1);
}
}
// 计算数字n的位数
int calc(int n) {
int res = 0;
while (n) {
res++;
n /= 10;
}
return res;
}
int main() {
cin >> n >> x; // 输入上限数字n和目标数字和x
len = calc(n); // 计算n的位数
dfs(0); // 从第0位开始生成数字
if (cnt == 0) {
cout << -1 << endl; // 没有符合条件的数字
} else {
// 输出所有符合条件的数字(注意:这里str数组只存储了最后一个数字)
for (int i = 1; i <= cnt; i++) {
cout << str[i] << endl;
}
cout << cnt << endl; // 输出符合条件的数字总数
}
return 0;
}
【运行结果】
1000 26
899
989
998
3
浙公网安备 33010602011771号