From a283f2a96f2fc62b887272ceddaee7433f4aaa22 Mon Sep 17 00:00:00 2001 From: Taj Date: Mon, 16 Nov 2020 19:39:52 +0000 Subject: [PATCH] Feat: added n_choose_r combinatorics algorithm (#1429) * feat: added n_choose_r combinatorial algorithm * fix: some type casting issue * fix: MathJax documentation fix * fix: MathJax documentation fix * fix: MathJax notation fix * fix: header comments Co-authored-by: David Leal * fix: suggested changes to documentation * updating DIRECTORY.md * fix: suggested changes * fix: suggested changes * fix: namespace closing comment Co-authored-by: David Leal * fix: removing a blank line Co-authored-by: David Leal * fix: link issue * fix: removed link * fix: removed newline Co-authored-by: David Leal Co-authored-by: David Leal Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 1 + math/n_choose_r.cpp | 81 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 math/n_choose_r.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 955518751..dcf0a6568 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -153,6 +153,7 @@ * [Miller Rabin](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/miller_rabin.cpp) * [Modular Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_exponentiation.cpp) * [Modular Inverse Fermat Little Theorem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_inverse_fermat_little_theorem.cpp) + * [N Choose R](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/n_choose_r.cpp) * [Number Of Positive Divisors](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/number_of_positive_divisors.cpp) * [Power For Huge Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/power_for_huge_numbers.cpp) * [Prime Factorization](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/prime_factorization.cpp) diff --git a/math/n_choose_r.cpp b/math/n_choose_r.cpp new file mode 100644 index 000000000..fa3287abc --- /dev/null +++ b/math/n_choose_r.cpp @@ -0,0 +1,81 @@ +/** + * @file + * @brief [Combinations](https://en.wikipedia.org/wiki/Combination) n choose r function implementation + * @details + * A very basic and efficient method of calculating + * choosing r from n different choices. + * \f$ \binom{n}{r} = \frac{n!}{r! (n-r)!} \f$ + * + * @author [Tajmeet Singh](https://github.com/tjgurwara99) + */ + +#include /// for io operations +#include /// for assert + +/** + * @namespace math + * @brief Mathematical algorithms + */ +namespace math { +/** + * @brief This is the function implementation of \f$ \binom{n}{r} \f$ + * @details + * We are calculating the ans with iterations + * instead of calculating three different factorials. + * Also, we are using the fact that + * \f$ \frac{n!}{r! (n-r)!} = \frac{(n - r + 1) \times \cdots \times n}{1 \times \cdots \times r} \f$ + * @tparam T Only for integer types such as long, int_64 etc + * @param n \f$ n \f$ in \f$ \binom{n}{r} \f$ + * @param r \f$ r \f$ in \f$ \binom{n}{r} \f$ + * @returns ans \f$ \binom{n}{r} \f$ + */ +template +T n_choose_r(T n, T r) { + if(r > n / 2) + r = n - r; // Because of the fact that nCr(n, r) == nCr(n, n - r) + T ans = 1; + for(int i = 1; i <= r; i++) { + ans *= n - r + i; + ans /= i; + } + return ans; +} +} // namespace math + +/** + * @brief Test implementations + * @returns void + */ +static void test() { + // First test on 5 choose 2 + uint8_t t = math::n_choose_r(5, 2); + assert(((void)"10 is the answer but function says otherwise.\n", + t == 10)); + std::cout << "First test passes." << std::endl; + // Second test on 5 choose 3 + t = math::n_choose_r(5, 3); + assert(((void)"10 is the answer but the function says otherwise.\n", + t == 10)); + std::cout << "Second test passes." << std::endl; + // Third test on 3 choose 2 + t = math::n_choose_r(3, 2); + assert(((void)"3 is the answer but the function says otherwise.\n", + t == 3)); + std::cout << "Third test passes." << std::endl; + // Fourth test on 10 choose 4 + t = math::n_choose_r(10, 4); + assert(((void)"210 is the answer but the function says otherwise.\n", + t == 210)); + std::cout << "Fourth test passes." << std::endl; +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + test(); // executing tests + return 0; +}