1 条题解
-
0
最小不同数字倍数问题题解
一、题目分析
题目要求找到正整数n的倍数m,使得m的十进制表示中不同数字的数量最少。若有多个解,输出数值最小的m。例如:
- 输入7,输出7(仅含数字7);
- 输入15,输出555(仅含数字5)。
二、算法思路
-
广度优先搜索(BFS):
- 按不同数字数量从小到大搜索(先搜1个数字,再搜2个数字,依此类推);
- 每个状态记录当前余数、位数、路径,避免重复计算。
-
剪枝优化:
- 若当前状态的位数已超过已知最优解,提前终止;
- 使用余数判重,避免处理重复状态。
-
字典序处理:
- 按数字组合的字典序生成候选集,确保找到的解为数值最小。
三、代码实现
#include<iostream> #include<cstdio> #include<cstring> #include<string> #define maxn 65540 using namespace std; int n, m, mcnt, tcnt, h; int a[5]; bool vis[maxn]; // 记录余数是否已访问,避免重复计算 string ans, tans; // 存储最终答案和临时答案 struct Node { int d, val, pre; // d:当前位数字,val:当前余数,pre:父节点索引 int cnt; // 位数 } cur, now, q[maxn]; // BFS队列 // 递归构建答案字符串 void getans(int k) { if (k == -1) return; getans(q[k].pre); tans += (char)(q[k].d + '0'); } // BFS搜索,使用k个不同数字 bool bfs(int k) { int head = 0, tail = -1; memset(vis, 0, sizeof(vis)); // 初始化队列,处理首位非零的情况 for (int i = 1; i <= k; i++) { if (a[i] != 0) { cur.cnt = 1; cur.d = a[i]; cur.pre = -1; cur.val = a[i] % n; vis[cur.val] = true; q[++tail] = cur; } } while (head <= tail) { now = q[head]; if (now.cnt > mcnt) break; // 剪枝:超过已知最优解位数 if (now.val == 0) { // 找到余数为0的解 h = head; tcnt = now.cnt; return true; } // 扩展状态 for (int i = 1; i <= k; i++) { int tval = (now.val * 10 + a[i]) % n; if (!vis[tval]) { vis[tval] = true; cur.cnt = now.cnt + 1; cur.d = a[i]; cur.pre = head; cur.val = tval; q[++tail] = cur; } } head++; } return false; } int main() { while (scanf("%d", &n) && n != 0) { int flag = 0; ans = "xx"; // 初始化为大值 mcnt = 1e9; // 初始最小位数为极大值 // 尝试用1个数字构造解 for (int i = 1; i <= 9; i++) { a[1] = i; if (bfs(1)) { tans = ""; getans(h); if (mcnt > tcnt || (mcnt == tcnt && ans > tans)) { ans = tans; mcnt = tcnt; } } } // 若找到解,输出并处理下一个测试用例 if (ans != "xx") { flag = 1; cout << ans << endl; } // 若1个数字无解,尝试用2个数字构造解 if (!flag) { for (int i = 0; i <= 9; i++) { a[1] = i; for (int j = i + 1; j <= 9; j++) { a[2] = j; if (bfs(2)) { tans = ""; getans(h); if (mcnt > tcnt || (mcnt == tcnt && ans > tans)) { ans = tans; mcnt = tcnt; } } } } cout << ans << endl; } } return 0; }
四、代码解释
-
数据结构:
Node
结构体记录当前状态(余数、位数、路径);vis
数组记录余数是否已访问,避免重复处理。
-
BFS搜索:
- 初始化队列时处理首位非零的情况;
- 每次扩展状态时,检查新余数是否已访问,避免循环;
- 找到余数为0的状态时,记录路径并返回。
-
答案构造:
getans
函数递归构造答案字符串,确保按正确顺序拼接数字;- 按字典序生成候选数字组合,确保优先找到数值最小的解。
五、示例解析
输入:15
- 搜索1个数字:尝试1-9,均无法整除15;
- 搜索2个数字:按字典序尝试组合(0,1)、(0,2)等,找到555(仅含数字5),满足条件。
- 输出:555
六、复杂度分析
- 时间复杂度:最坏情况O(n×10),其中n为输入数值;
- 空间复杂度:O(n),主要用于存储余数判重数组和BFS队列。
七、关键技巧
- 余数判重:利用模运算特性,避免处理重复余数状态;
- 字典序生成:按顺序生成候选数字组合,确保优先找到最小数值解;
- 剪枝优化:提前终止超过已知最优解位数的状态,减少搜索空间。
- 1
信息
- ID
- 1284
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者