Files
C-Plus-Plus/dynamic_programming/partition_problem.cpp
2021-11-10 07:42:34 +05:30

110 lines
4.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/******************************************************************************
* @file
* @brief Implementation of the [Partition
* Problem](https://en.wikipedia.org/wiki/Partition_problem )
* @details
* The partition problem, or number partitioning, is the task of deciding
* whether a given multiset S of positive integers can be partitioned into two
* subsets S1 and S2 such that the sum of the numbers in S1 equals the sum of
* the numbers in S2. Although the partition problem is NP-complete, there is a
* pseudo-polynomial time dynamic programming solution, and there are heuristics
* that solve the problem in many instances, either optimally or approximately.
* For this reason, it has been called "the easiest hard problem".
*
* The worst case time complexity of Jarviss Algorithm is O(n^2). Using
* Grahams scan algorithm, we can find Convex Hull in O(nLogn) time.
*
* ### Implementation
*
* Step 1
* Calculate sum of the array. If sum is odd, there can not be two subsets with
* equal sum, so return false.
*
* Step 2
* If sum of array elements is even, calculate sum/2 and find a subset of array
* with sum equal to sum/2.
*
* @author [Lajat Manekar](https://github.com/Lazeeez)
*
*******************************************************************************/
#include <iostream> /// for IO Operations
#include <numeric> /// for std::accumulate
#include <vector> /// for std::vector
#include <cassert> /// for assert
/******************************************************************************
* @namespace dp
* @brief Dynamic programming algorithms
*******************************************************************************/
namespace dp {
/******************************************************************************
* @namespace partitionProblem
* @brief Partition problem algorithm
*******************************************************************************/
namespace partitionProblem {
/******************************************************************************
* @brief Returns true if arr can be partitioned in two subsets of equal sum,
* otherwise false
* @param arr vector containing elements
* @param size Size of the vector.
* @returns @param bool whether the vector can be partitioned or not.
*******************************************************************************/
bool findPartiion(const std::vector<uint64_t> &arr, uint64_t size) {
uint64_t sum = std::accumulate(arr.begin(), arr.end(),
0); // Calculate sum of all elements
if (sum % 2 != 0) {
return false; // if sum is odd, it cannot be divided into two equal sum
}
std::vector<bool> part;
// bool part[sum / 2 + 1];
// Initialize the part array as 0
for (uint64_t it = 0; it <= sum / 2; ++it) {
part.push_back(false);
}
// Fill the partition table in bottom up manner
for (uint64_t it = 0; it < size; ++it) {
// The element to be included in the sum cannot be greater than the sum
for (uint64_t it2 = sum / 2; it2 >= arr[it];
--it2) { // Check if sum - arr[i]
// ould be formed from a subset using elements before index i
if (part[it2 - arr[it]] == 1 || it2 == arr[it]) {
part[it2] = true;
}
}
}
return part[sum / 2];
}
} // namespace partitionProblem
} // namespace dp
/*******************************************************************************
* @brief Self-test implementations
* @returns void
*******************************************************************************/
static void test() {
std::vector<uint64_t> arr = {{1, 3, 3, 2, 3, 2}};
uint64_t n = arr.size();
bool expected_result = true;
bool derived_result = dp::partitionProblem::findPartiion(arr, n);
std::cout << "1st test: ";
if (expected_result == derived_result) {
std::cout << "Passed!" << std::endl;
} else {
std::cout << "Failed!" << std::endl;
}
}
/*******************************************************************************
* @brief Main function
* @returns 0 on exit
*******************************************************************************/
int main() {
test(); // run self-test implementations
return 0;
}