紫书刷题进行中,题解系列【GitHub|CSDN】
例题7-1 UVA725 Division(21行AC代码)
题目大意
给定整数N,按字典序输出满足等式abcde/fghij=N
的值,其中a~j
为[0,9]
的一个排列,0可以在首位
思路分析
若是直接枚举0-9的全排列,枚举量为10!,但仔细分析,假设存在等式P/Q=N
,因为N已知,只要求出P,即可计算出Q,因此可将枚举量降至
,对于每个P,若能整除N,那么只需判断P和Q是否存在重复数字即可。
再仔细思考一下,发现也没有必要枚举所有的P或Q,假设从1234开始枚举Q,只要发现P或Q任意一个位数大于5,说明之后不会存在解,即可停止,这种方式只需1万多次枚举
对于判重存在多种方法:
- 用set存储每一位,判断是否有重复
- 用hash表记录个数
- 排序后看是否为0-9有序序列
注意点
- 可用sprintf完成数值到字符串的格式转换,注意string此时不可直接作为接受字符串,需用字符数组
AC代码(C++11,分析优化)
#include<bits/stdc++.h>
using namespace std;
int N, num=0;
int main() {
while (scanf("%d", &N) == 1 && N != 0) {
if (num != 0) puts(""); num++; // 连续的测试用例间需有空行
char buf[100]; string s; int cnt=0;
for (int fj=1234; ; fj++) { // 枚举1234 - 98765
sprintf(buf, "%05d%05d", fj*N, fj); // 分子,分母转为字符串
s = buf;
if (s.size() > 10) break; // 其中一个超过5位数
unordered_set<char> _set(s.begin(), s.end()); // 判重
if (_set.size() == 10) { // 刚好整除且无重复数字
printf("%s / %s = %d\n", s.substr(0,5).c_str(), s.substr(5).c_str(), N);
cnt ++;
}
}
if (cnt == 0) printf("There are no solutions for %d.\n", N);
}
return 0;
}