Skip to content

Instantly share code, notes, and snippets.

@iafisher
Last active August 29, 2015 14:19
Show Gist options
  • Save iafisher/975b1708216f13f3e4fc to your computer and use it in GitHub Desktop.
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)
#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
#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