Problem 32 : Pandigital products
We shall say that an n-digit number is pandigital if it makes use of all the digits 1 to n exactly once; for example, the 5-digit number, 15234, is 1 through 5 pandigital.
The product 7254 is unusual, as the identity, 39 × 186 = 7254, containing multiplicand, multiplier, and product is 1 through 9 pandigital.
Find the sum of all products whose multiplicand/multiplier/product identity can be written as a 1 through 9 pandigital.
HINT: Some products can be obtained in more than one way so be sure to only include it once in your sum.
C++ source code
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <ctime>
#include <cassert>
using namespace std;
class PE0032
{
private:
set<int> m_products_s;
bool checkNumberDigits(int number);
vector<int> getDigits(int number);
vector<int> Intersection(vector<int>& v1, vector<int>& v2, vector<int>& v3);
void getPandigitalProducts();
public:
bool checkPandigital(int multiplicand, int multiplier, int product);
int PE0032::getSumOfProducts();
};
bool PE0032::checkNumberDigits(int number)
{
set<int> digits_s;
int i = 0;
while(number>0)
{
if (0 == number%10)
{
return false;
}
else
{
digits_s.insert(number%10);
number /= 10;
i++;
}
}
if (i != digits_s.size())
{
return false;
}
else
{
return true;
}
}
vector<int> PE0032::getDigits(int number)
{
vector<int>digits_v;
while(number>0)
{
digits_v.push_back(number%10);
number /= 10;
}
return digits_v;
}
vector<int> PE0032::Intersection(vector<int>& v1, vector<int>& v2, vector<int>& v3)
{
vector<int>::iterator iter;
for(iter=v1.begin(); iter!=v1.end(); iter++)
{
v3.push_back(*iter);
}
for(iter=v2.begin(); iter!=v2.end(); iter++)
{
v3.push_back(*iter);
}
sort(v3.begin(), v3.end());
return v3;
}
int PE0032::getSumOfProducts()
{
getPandigitalProducts();
set<int>::iterator iter;
int sum = 0;
for(iter=m_products_s.begin(); iter!=m_products_s.end(); iter++)
{
sum += *iter;
}
return sum;
}
bool PE0032::checkPandigital(int multiplicand, int multiplier, int product)
{
vector<int> multiplicand_v = getDigits(multiplicand);
vector<int> multiplier_v = getDigits(multiplier);
vector<int> product_v = getDigits(product);
vector<int> res = Intersection(multiplicand_v, multiplier_v, product_v);
if (res.size() != 9)
{
return false;
}
for(int i=1; i<=9; i++)
{
if (res[i-1] != i)
{
return false;
}
}
return true;
}
void PE0032::getPandigitalProducts()
{
for(int multiplier=2; multiplier<2000; multiplier++)
{
if (false == checkNumberDigits(multiplier))
{
continue;
}
for(int multiplicand=1;
multiplicand<multiplier && multiplicand<9876/multiplier;
multiplicand++)
{
if (false == checkNumberDigits(multiplicand))
{
continue;
}
// 9876 = 4 * 2351
// 9876 = 54 * 213
int product = multiplicand * multiplier;
if (false == checkNumberDigits(product))
{
continue;
}
if (true == checkPandigital(multiplicand, multiplier, product))
{
#ifdef UNIT_TEST
cout << product << " = " << multiplicand << " x "<<multiplier<<endl;
#endif
m_products_s.insert(product);
}
}
}
#ifdef UNIT_TEST
copy(m_products_s.begin(), m_products_s.end(), ostream_iterator<int>(cout, " "));
cout << endl;
#endif
}
int main()
{
clock_t start = clock();
PE0032 pe0032;
assert(true == pe0032.checkPandigital(39, 186, 7254));
cout << "The sum of all products whose multiplicand/multiplier/product " << endl;
cout << "identity can be written as a 1 through 9 pandigital is " ;
cout << pe0032.getSumOfProducts() << endl;
clock_t finish = clock();
double duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "C/C++ running time: " << duration << " seconds" << endl;
return 0;
}
Python source code
def checkPandigital(s, d=9):
"""
check whether digits string is pandigital
s: digits string. d: number of digits (default 9)
"""
return len(s)==d and not '1234567890'[:d].strip(s)
def checkPandigitalProduct(multiplicand, multiplier, product):
s = str(multiplicand)+str(multiplier)+str(product)
return checkPandigital(s)
def checkNumberDigits(number):
"""
if number contains digit 0 or duplicated digits, return False
"""
s = str(number) # 4076 -> '4076'
digits = list(set(s)) # '4066' -> ['4','0',6']
if len(digits) != len(s) or '0' in digits: # ['4','0','6']
return False
return True
def getPandigitalProducts():
"""
get all Pandigital Products and put them into set products_s
"""
products_s = set()
for multiplier in range(2, 2000):
if False == checkNumberDigits(multiplier):
continue
multiplicand = 1
while multiplicand < multiplier and multiplicand < 9876/multiplier:
if False == checkNumberDigits(multiplicand):
multiplicand += 1
continue
product = multiplicand * multiplier # 9876 = 54 * 213
if False == checkNumberDigits(product):
multiplicand += 1
continue
if True == checkPandigitalProduct(multiplicand, multiplier, product):
#print(product,"=",multiplicand,"x",multiplier)
products_s.add(product)
multiplicand += 1
return products_s
def getSumOfProducts():
products_s = getPandigitalProducts()
return sum(products_s)
def main():
assert True == checkPandigitalProduct(39, 186, 7254)
print("The sum of all products whose multiplicand/multiplier/product")
print("identity can be written as a 1 through 9 pandigital is",getSumOfProducts())
if __name__ == '__main__':
main()