Here's the challenge:
Once upon a time in a strange situation, people called a number ugly if it was divisible by any of the one-digit primes (\$2\$, \$3\$, \$5\$ or \$7\$). Thus, \$14\$ is ugly, but \$13\$ is fine. \$39\$ is ugly, but \$121\$ is not. Note that \$0\$ is ugly. Also note that negative numbers can also be ugly: \$-14\$ and \$-39\$ are examples of such numbers.
One day on your free time, you are gazing at a string of digits, something like:
123456
You are amused by how many possibilities there are if you are allowed to insert plus or minus signs between the digits. For example you can make:
1 + 234 - 5 + 6 = 236
which is ugly. Or:
123 + 4 - 56 = 71
which is not ugly.
It is easy to count the number of different ways you can play with the digits: Between each two adjacent digits you may choose put a plus sign, a minus sign, or nothing. Therefore, if you start with N digits there are \$3^{N-1}\$ expressions you can make. Note that it is fine to have leading zeros for a number. If the string is '
01023
', then '01023
', '0+1-02+3
' and '01-023
' are legal expressions.Your task is simple: Among the \$3^{N-1}\$ expressions, count how many of them evaluate to an ugly number.
Input Sample:
Your program should accept as its first argument a path to a filename. Each line in this file is one test case. Each test case will be a single line containing a non-empty string of decimal digits. The string in each test case will be non-empty and will contain only characters '\$0\$' through '\$9\$'. Each string is no more than 13 characters long. E.g.
1 9 011 12345
Output Sample:
Print out the number of expressions that evaluate to an ugly number for each test case, each one on a new line. E.g.
0 1 6 64
Is the code understandable? How can it be improved?
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <bitset>
#include <cmath>
#include <sstream>
#include <numeric>
using namespace std;
const int one_prime[4] = {2,3,5,7};
bool isUgly(int number)
{
if(number == 0) return true;
for(int i=0; i<4; i++)
{
if(number % one_prime[i] == 0)
return true;
}
return false;
}
vector<string> makeBinary(size_t perm)
{
vector<string> output;
size_t eraseLength = bitset<32>(perm).to_string().find_first_of('1');
while(perm--)
{
string binary = bitset<32>(perm).to_string();
binary.erase(binary.begin(), binary.begin() + eraseLength);
output.push_back(binary);
}
return output;
}
vector<string> getPartitions(const vector<string>& binarySet, const string& input)
{
vector<string> binOperator;
for(size_t idx = 0; idx < binarySet.size(); idx++)
{
string str(input);
for(size_t pos = 0,opCount = 1; (pos = binarySet[idx].find('1',pos) )!= string::npos; pos++,opCount++)
str.insert(pos+opCount, " ");
binOperator.push_back(str);
}
return binOperator;
}
vector<int> makePartitionsToNum(const string& str)
{
vector<int> numbers;
stringstream split(str);
string buf;
while(split >> buf)
{
int value;
istringstream toNum(buf);
toNum >> value;
numbers.push_back(value);
}
return numbers;
}
void getReadyNumbers(vector<int>* readyNumbers, const vector<int> &numbers)
{
if(numbers.size() == 1)
{
(*readyNumbers).push_back(numbers[0]);
}
else if(numbers.size() == 2)
{
(*readyNumbers).push_back(numbers[0] + numbers[1]);
(*readyNumbers).push_back(numbers[0] - numbers[1]);
}
else
{
size_t possiblePerm = pow(2,static_cast<double>(numbers.size() - 1) );
vector<string> binSet(makeBinary(possiblePerm));
for(size_t i=0; i<binSet.size(); i++)
{
int result = numbers[0];
for(size_t binCounter=1; binCounter<numbers.size(); binCounter++)
{
if(binSet[i][binCounter - 1] == '1')
{
result += numbers[binCounter];
}
else
{
result -= numbers[binCounter];
}
}
(*readyNumbers).push_back(result);
}
}
}
void PrintSolution(const vector<int>& readyNumbers)
{
size_t UglyNumberCount = 0;
for(size_t i=0; i<readyNumbers.size(); i++)
{
if(isUgly(readyNumbers[i]))
{
UglyNumberCount++;
}
}
cout << UglyNumberCount << endl;
}
int main(int argc, char *argv[])
{
ifstream stream(argv[1]);
string input;
while (getline(stream, input))
{
size_t perm = pow(2,static_cast<double>(input.size() - 1) );
vector<string> binarySet(makeBinary(perm));
vector<string> partitionSet (getPartitions(binarySet, input));
vector<int> readyNumbers;
for(size_t idx=0; idx<partitionSet.size(); idx++)
{
vector<int> numbers(makePartitionsToNum(partitionSet[idx]));
getReadyNumbers(&readyNumbers,numbers);
}
PrintSolution(readyNumbers);
}
return 0;
}