diff --git a/include/0005_DynamicProgramming/0001_RodCutting.h b/include/0005_DynamicProgramming/0001_RodCutting.h new file mode 100644 index 0000000..f39ffe2 --- /dev/null +++ b/include/0005_DynamicProgramming/0001_RodCutting.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include +using namespace std; + +namespace RodCutting +{ + class DynamicProgramming + { + private: + int _totalLength; + vector _price; + vector _cutPositions; + public: + DynamicProgramming(vector price); + int RecursiveRodCutting(int length); + pair> DpGetMaximumProfitWithCuts(int length); + }; +} \ No newline at end of file diff --git a/source/0005_DynamicProgramming/0001_RodCutting.cc b/source/0005_DynamicProgramming/0001_RodCutting.cc new file mode 100644 index 0000000..a382702 --- /dev/null +++ b/source/0005_DynamicProgramming/0001_RodCutting.cc @@ -0,0 +1,61 @@ +#include "../../include/0005_DynamicProgramming/0001_RodCutting.h" +#include +#include +using namespace std; + +namespace RodCutting +{ + DynamicProgramming::DynamicProgramming(vector price) + { + this->_price = price; + this->_totalLength = this->_price.size(); + } + + int DynamicProgramming::RecursiveRodCutting(int length) + { + // Base case + if (length == 0) + { + return 0; + } + + int result = 0; + + for (int cut = 1; cut <= length; cut++) + { + result = max(result, this->_price[cut - 1] + this->RecursiveRodCutting(length - cut)); + } + + return result; + } + + pair> DynamicProgramming::DpGetMaximumProfitWithCuts(int length) + { + vector dp(this->_price.size() + 1, 0); + this->_cutPositions = vector(this->_price.size() + 1, 0); + + // Find maximum value for all rod of length i. + for (int i = 1; i <= this->_totalLength; i++) + { + for (int j = 1; j <= i; j++) + { + if (dp[i] < (this->_price[j - 1] + dp[i - j])) + { + dp[i] = this->_price[j - 1] + dp[i - j]; + this->_cutPositions[i] = j - 1; + } + } + } + + // Re-construct the cuts + vector cutLengths; + int currentLength = length; + while (currentLength > 0) + { + cutLengths.push_back(this->_cutPositions[currentLength] + 1); + currentLength -= cutLengths.back(); + } + + return { dp[length] ,cutLengths }; + } +} \ No newline at end of file diff --git a/source/0005_DynamicProgramming/CMakeLists.txt b/source/0005_DynamicProgramming/CMakeLists.txt index e69de29..64fd7f7 100644 --- a/source/0005_DynamicProgramming/CMakeLists.txt +++ b/source/0005_DynamicProgramming/CMakeLists.txt @@ -0,0 +1,8 @@ +# Specify the source files +set(0005DYNAMICPROGRAMMING_SOURCES + 0001_RodCutting.cc + +) + +# Create a library target +add_library(0005DYNAMICPROGRAMMING ${0005DYNAMICPROGRAMMING_SOURCES}) \ No newline at end of file diff --git a/test/0005_DynamicProgramming/0001_RodCuttingTest.cc b/test/0005_DynamicProgramming/0001_RodCuttingTest.cc new file mode 100644 index 0000000..966a247 --- /dev/null +++ b/test/0005_DynamicProgramming/0001_RodCuttingTest.cc @@ -0,0 +1,40 @@ +#include +#include "../../include/0005_DynamicProgramming/0001_RodCutting.h" +#include "../0000_CommonUtilities/UnitTestHelper.h" + +namespace RodCutting +{ + UnitTestHelper unitTestHelper; + + TEST(DpRodCutting, RecursiveTest) + { + // Arrange + vector price = { 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 }; + int length = 8; + DynamicProgramming dp(price); + int expectedResult = 22; + + // Act + int actualResult = dp.RecursiveRodCutting(length); + + // Assert + ASSERT_EQ(actualResult, expectedResult); + } + + TEST(DpRodCutting, DpTest) + { + // Arrange + vector price = { 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 }; + int length = 8; + DynamicProgramming dp(price); + int expectedProfit = 22; + vector expectedCuts = { 2, 6 }; + + // Act + pair> actualResult = dp.DpGetMaximumProfitWithCuts(length); + + // Assert + ASSERT_EQ(actualResult.first, expectedProfit); + ASSERT_EQ(actualResult.second, expectedCuts); + } +} \ No newline at end of file diff --git a/test/0005_DynamicProgramming/CMakeLists.txt b/test/0005_DynamicProgramming/CMakeLists.txt index e69de29..899a9a5 100644 --- a/test/0005_DynamicProgramming/CMakeLists.txt +++ b/test/0005_DynamicProgramming/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_policy(SET CMP0135 NEW) + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +enable_testing() + +add_executable( + 0005DynamicProgrammingTests + 0001_RodCuttingTest.cc + +) + +target_link_libraries( + 0005DynamicProgrammingTests + GTest::gtest_main + 0005DYNAMICPROGRAMMING +) + +# Add .clang-tidy configuration to this library. +if(CLANG_TIDY_EXE) + set_target_properties(0005DYNAMICPROGRAMMING PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}") +endif() + +include(GoogleTest) +gtest_discover_tests(0005DynamicProgrammingTests DISCOVERY_TIMEOUT 30) \ No newline at end of file