我的方法大致如下。这是一个递归算法,使用一个集合S,其中包含数字2到9,可能会多次出现。
try (N, S, digit) {
for d = digit, digit-1, ..., 2 {
if N is divisible by d then {
S' = S + {d};
if N/d is composed of all the digits in S', perhaps with
some 1's thrown in, then N/d is an answer;
try (N/d, S', d);
}
}
}
然后针对原始数字进行操作。
try (originalN, empty-set, 9);
also check originalN to see if it has only 1 digits (11, 11111, etc.); if so, then it's also an answer
我认为这个方法可行,但可能会忽略掉一些边界情况。
对于4977,try(4977,empty,9)
将发现4977可被9整除,因此它调用了try(553,{9},9)
。内部的 try
发现553是可被7整除的,553/7 = 79; 这时S' = {7, 9},算法检查是否由数字 {7, 9}组成79,这一步成功了。虽然算法继续执行,但最终我们会回溯到外部的 try
,在某个时刻尝试 d = 7
,并且4977/7 = 711,在进行检查时,S' = {7} 并且711由7和一些1组成,因此也是一种答案。
编辑:我已经包含了完整的C ++函数:
#include <iostream>
#include <vector>
using namespace std;
struct digitMultiset {
int counts[10];
};
static const digitMultiset empty = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
bool hasDigits (const int n, digitMultiset& s) {
digitMultiset s2 = empty;
int temp = n;
int digit;
while (temp > 0) {
digit = temp % 10;
if (digit == 0) return false;
if (digit != 1) s2.counts[digit]++;
temp /= 10;
}
for (int d = 2; d < 10; d++)
if (s2.counts[d] != s.counts[d]) return false;
return true;
}
void tryIt (const int currval, const digitMultiset& s,
const int digit, vector<int>& answers) {
digitMultiset newS;
for (int d = digit; d >= 2; d--) {
if (currval % d == 0) {
int quotient = currval / d;
newS = s;
newS.counts[d]++;
if (hasDigits (quotient, newS))
answers.push_back (quotient);
tryIt (quotient, newS, d, answers);
}
}
}
void seedProduct (const int val) {
vector<int> answers;
tryIt (val, empty, 9, answers);
int temp = val;
bool allOnes = true;
while (temp > 0) {
if (temp % 10 != 1) {
allOnes = false;
break;
}
temp /= 10;
}
if (allOnes)
answers.push_back(val);
int count = answers.size();
if (count > 0) {
if (count == 1)
cout << val << " has seed product " << answers[0] << endl;
else {
cout << val << " has " << count << " seed products: ";
for (int& ans : answers)
cout << ans << " ";
cout << endl;
}
}
}