Last active
August 29, 2015 14:19
-
-
Save iafisher/975b1708216f13f3e4fc to your computer and use it in GitHub Desktop.
Given a set of four numbers, finds the combination of arithmetic operations (if it exists) that creates 24. Works for arbitrary targets and set sizes (including fractions and negative numbers)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef RATIONAL_NUMBER_H_INCLUDED | |
#define RATIONAL_NUMBER_H_INCLUDED | |
#include <ostream> | |
#include <sstream> | |
#include <string> | |
struct RationalNumber | |
{ | |
int numerator, denominator; | |
RationalNumber(int num): numerator(num), denominator(1) {} | |
RationalNumber(int num, int den): numerator(num), denominator(den) | |
{ | |
simplify(); | |
} | |
RationalNumber(const RationalNumber& n) | |
{ | |
numerator = n.get_numerator(); | |
denominator = n.get_denominator(); | |
simplify(); | |
} | |
int get_numerator() const | |
{ | |
return numerator; | |
} | |
int get_denominator() const | |
{ | |
return denominator; | |
} | |
bool is_nonzero() const | |
{ | |
return numerator != 0; | |
} | |
bool operator==(const RationalNumber& n) const | |
{ | |
if (numerator == 0) | |
{ | |
return n.get_numerator() == 0; | |
} else if (denominator == n.get_denominator()) | |
{ | |
return numerator == n.get_numerator(); | |
} else | |
{ | |
return numerator * n.get_denominator() == n.get_numerator() * denominator; | |
} | |
} | |
bool operator!=(const RationalNumber& n) const | |
{ | |
return numerator != n.get_numerator() || denominator != n.get_denominator(); | |
} | |
bool operator>(const RationalNumber& n) const | |
{ | |
return (numerator * n.get_denominator()) > (n.get_numerator() * denominator); | |
} | |
bool operator<(const RationalNumber& n) const | |
{ | |
return (numerator * n.get_denominator()) < (n.get_numerator() * denominator); | |
} | |
bool operator>=(const RationalNumber& n) const | |
{ | |
return (numerator * n.get_denominator()) >= (n.get_numerator() * denominator); | |
} | |
bool operator<=(const RationalNumber& n) const | |
{ | |
return (numerator * n.get_denominator()) <= (n.get_numerator() * denominator); | |
} | |
void simplify() | |
{ | |
if ((denominator < 0 && numerator < 0) || denominator < 0) | |
{ | |
denominator *= -1; | |
numerator *= -1; | |
} | |
if (numerator == 0) | |
{ | |
denominator = 1; | |
} else if (denominator != 0 && numerator != 1) | |
{ | |
int gcd = 1; | |
for (int i = 2; i <= denominator; i++) | |
{ | |
if (numerator % i == 0 && denominator % i == 0) | |
{ | |
gcd = i; | |
} | |
} | |
numerator /= gcd; | |
denominator /= gcd; | |
} | |
} | |
std::string str() const | |
{ | |
std::stringstream ss; | |
if (denominator == 1) | |
{ | |
ss << numerator; | |
return ss.str(); | |
} else | |
{ | |
ss << "(" << numerator << "/" << denominator << ")"; | |
return ss.str(); | |
} | |
} | |
}; | |
std::ostream& operator<<(std::ostream& out, const RationalNumber& n) | |
{ | |
out << n.str(); | |
return out; | |
} | |
RationalNumber operator+(const RationalNumber& n1, const RationalNumber& n2) | |
{ | |
int num = n1.get_numerator() * n2.get_denominator() + n2.get_numerator() * n1.get_denominator(); | |
int den = n1.get_denominator() * n2.get_denominator(); | |
return RationalNumber(num, den); | |
} | |
RationalNumber operator-(const RationalNumber& n1, const RationalNumber& n2) | |
{ | |
int num = n1.get_numerator() * n2.get_denominator() - n2.get_numerator() * n1.get_denominator(); | |
int den = n1.get_denominator() * n2.get_denominator(); | |
return RationalNumber(num, den); | |
} | |
RationalNumber operator*(const RationalNumber& n1, const RationalNumber& n2) | |
{ | |
int num = n1.get_numerator() * n2.get_numerator(); | |
int den = n1.get_denominator() * n2.get_denominator(); | |
return RationalNumber(num, den); | |
} | |
RationalNumber operator/(const RationalNumber& n1, const RationalNumber& n2) | |
{ | |
if (!n2.is_nonzero()) | |
{ | |
throw "divide by zero"; | |
} | |
int num = n1.get_numerator() * n2.get_denominator(); | |
int den = n1.get_denominator() * n2.get_numerator(); | |
return RationalNumber(num, den); | |
} | |
#endif // RATIONAL_NUMBER_H_INCLUDED |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdlib> | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include "rational_number.h" | |
#define GIVEN_NUMBERS 4 | |
#define DEFAULT_TARGET 24 | |
using namespace std; | |
bool brute_force_combo(vector<RationalNumber>, RationalNumber, string); | |
int main() | |
{ | |
cout << "Enter the numbers:\n"; | |
string tmp; | |
vector<RationalNumber> nums; | |
for (int i = 0; i < GIVEN_NUMBERS; i++) | |
{ | |
getline(cin, tmp); | |
/// Get the numbers (possibly fractions) | |
if (!tmp.empty()) | |
{ | |
size_t slash_pos = tmp.find('/'); | |
if (slash_pos == string::npos) | |
{ | |
int n = atoi(tmp.c_str()); | |
nums.push_back(RationalNumber(n)); | |
} else | |
{ | |
int num = atoi(tmp.substr(0, slash_pos).c_str()); | |
int den = atoi(tmp.substr(slash_pos + 1).c_str()); | |
nums.push_back(RationalNumber(num, den)); | |
} | |
} | |
} | |
cout << '\n'; | |
brute_force_combo(nums, RationalNumber(DEFAULT_TARGET), ""); | |
return 0; | |
} | |
bool brute_force_combo(vector<RationalNumber> nums, RationalNumber target, string output) | |
{ | |
/// If the set contains only two numbers, attempt to combine them | |
if (nums.size() == 2) | |
{ | |
if (nums[0] + nums[1] == target) | |
{ | |
/// Output the previous operations as well as the current one | |
cout << output << nums[0] << "+" << nums[1] << '\n'; | |
return true; | |
} else if (nums[0] - nums[1] == target) | |
{ | |
cout << output << nums[0] << "-" << nums[1] << '\n'; | |
return true; | |
} else if (nums[1] - nums[0] == target) | |
{ | |
cout << output << nums[1] << "-" << nums[0] << '\n'; | |
return true; | |
} else if (nums[0] * nums[1] == target) | |
{ | |
cout << output << nums[0] << "*" << nums[1] << '\n'; | |
return true; | |
} else if (nums[1].is_nonzero() && nums[0] / nums[1] == target) | |
{ | |
cout << output << nums[0] << "/" << nums[1] << '\n'; | |
return true; | |
} else if (nums[0].is_nonzero() && nums[1] / nums[0] == target) | |
{ | |
cout << output << nums[1] << "/" << nums[0] << '\n'; | |
return true; | |
} | |
} else | |
{ | |
/// Loop through every pair of the set | |
for (size_t i = 0; i < nums.size(); i++) | |
{ | |
for (size_t j = i + 1; j < nums.size(); j++) | |
{ | |
vector<RationalNumber> tmp; | |
RationalNumber n1(nums[i]); | |
RationalNumber n2(nums[j]); | |
/// Copy the set into tmp, except for the two elements of the pair | |
for (size_t k = 0; k < nums.size(); k++) | |
{ | |
if (k != i && k != j) | |
{ | |
tmp.push_back(nums[k]); | |
} | |
} | |
/// Combine the pair in every possible way, then try to generate the | |
/// target using the new set | |
tmp.push_back(n1 + n2); | |
if (brute_force_combo(tmp, target, output + n1.str() + '+' + n2.str() + '\n')) | |
{ | |
return true; | |
} | |
tmp.pop_back(); | |
tmp.push_back(n1 - n2); | |
if (brute_force_combo(tmp, target, output + n1.str() + '-' + n2.str() + '\n')) | |
{ | |
return true; | |
} | |
tmp.pop_back(); | |
tmp.push_back(n2 - n1); | |
if (brute_force_combo(tmp, target, output + n2.str() + '-' + n1.str() + '\n')) | |
{ | |
return true; | |
} | |
tmp.pop_back(); | |
tmp.push_back(n1 * n2); | |
if (brute_force_combo(tmp, target, output + n1.str() + '*' + n2.str() + '\n')) | |
{ | |
return true; | |
} | |
tmp.pop_back(); | |
if (n2.is_nonzero()) | |
{ | |
tmp.push_back(n1 / n2); | |
if (brute_force_combo(tmp, target, output + n1.str() + '/' + n2.str() + '\n')) | |
{ | |
return true; | |
} | |
tmp.pop_back(); | |
} | |
if (n1.is_nonzero()) | |
{ | |
tmp.push_back(n2 / n1); | |
if (brute_force_combo(tmp, target, output + n2.str() + '/' + n1.str() + '\n')) | |
{ | |
return true; | |
} | |
tmp.pop_back(); | |
} | |
} | |
} | |
} | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment