diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 267b2ec..783d168 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -15,6 +15,7 @@ jobs: steps: - name: Install gtest manually run: sudo apt-get install libgtest-dev + run: sudo apt install libomp-dev - uses: actions/checkout@v3 diff --git a/lib/src/util.cpp b/lib/src/util.cpp index 81e15bd..2f00b78 100644 --- a/lib/src/util.cpp +++ b/lib/src/util.cpp @@ -1 +1,24 @@ #include "util.hpp" + +void MergeSort(std::vector& array) { + int n = array.size(); + std::vector buffer(n); + + for (int slice = 1; slice < n; slice *= 2) { + for (int left = 0; left < n; left += 2 * slice) { + int mid = std::min(left + slice, n); + int right = std::min(left + 2 * slice, n); + + int i = left, j = mid; + int k = left; + while (i < mid && j < right) { + buffer[k++] = array[i] <= array[j] ? array[i++] : array[j++]; + } + while (i < mid) buffer[k++] = array[i++]; + while (j < right) buffer[k++] = array[j++]; + + std::copy(buffer.begin() + left, buffer.begin() + right, + array.begin() + left); + } + } +} \ No newline at end of file diff --git a/lib/src/util.hpp b/lib/src/util.hpp index e69de29..fd0b3e2 100644 --- a/lib/src/util.hpp +++ b/lib/src/util.hpp @@ -0,0 +1,3 @@ +#include + +void MergeSort(std::vector& array); diff --git a/sandbox/template/src/main b/sandbox/template/src/main new file mode 100755 index 0000000..c89b0c2 Binary files /dev/null and b/sandbox/template/src/main differ diff --git a/sandbox/template/src/main.cpp b/sandbox/template/src/main.cpp index 0e4393b..f46e229 100644 --- a/sandbox/template/src/main.cpp +++ b/sandbox/template/src/main.cpp @@ -1,3 +1,41 @@ -#include +// #include +// #include -int main() { return 0; } +// void MergeSort(std ::vector& array) { +// int i{0}, j{1}; +// int slice{1}; +// do { +// while (j <= array.size() - 1) { +// if (array[i] > array[j]) { +// iter_swap(array.begin() + i, array.begin() + j); + +// ++j; +// } else +// ++i; +// if (j - i > slice) { +// i = j; +// j = i + slice; +// } else if (j == i) { +// i += 1; +// j = i + slice; +// } +// } +// slice *= 2; +// slice > array.size() ? j = array.size() - 1 : j = slice; +// i = 0; +// if (j == array.size() - 1) { +// if (i == 0) { +// return; +// } +// } +// } while (true); +// } + +int main() { + // std ::vector unsort{3, 2, 4, 5, 1, 9, 7}; + // MergeSort(unsort); + // for (int i = 0; i < unsort.size(); ++i) { + // std ::cout << unsort[i] << " "; + // } + // std ::cout << std ::endl; +} diff --git a/sandbox/template/src/test.cpp b/sandbox/template/src/test.cpp index 31df8b8..7b3eb4a 100644 --- a/sandbox/template/src/test.cpp +++ b/sandbox/template/src/test.cpp @@ -1,8 +1,8 @@ -#include +// #include -#include +// #include -#include "utils.hpp" +// #include "utils.hpp" -TEST(Template, Simple) { ASSERT_EQ(true, true); } +// TEST(Template, Simple) { ASSERT_EQ(true, true); } diff --git a/sandbox/template/src/utils.cpp b/sandbox/template/src/utils.cpp index 0ee624c..03b9030 100644 --- a/sandbox/template/src/utils.cpp +++ b/sandbox/template/src/utils.cpp @@ -1 +1 @@ -#include "utils.hpp" +// #include "utils.hpp" diff --git a/sandbox/template/src/utils.hpp b/sandbox/template/src/utils.hpp index 6f70f09..7dcceab 100644 --- a/sandbox/template/src/utils.hpp +++ b/sandbox/template/src/utils.hpp @@ -1 +1 @@ -#pragma once +// #pragma once diff --git a/task_01/src/find.cpp b/task_01/src/find.cpp new file mode 100644 index 0000000..b5d0413 --- /dev/null +++ b/task_01/src/find.cpp @@ -0,0 +1,20 @@ +#include "find.hpp" + +std ::vector FindNums(int k, std ::vector sequence) { + if (sequence.size() == 0) throw NoSumNum{}; + + std ::vector answer; + unsigned long left_index{0}; + unsigned long right_index{sequence.size() - 1}; + while (left_index != right_index) { + if ((sequence[left_index] + sequence[right_index]) == k) { + answer.push_back(sequence[left_index]); + answer.push_back(sequence[right_index]); + return answer; + } else if (sequence[left_index] + sequence[right_index] > k) + --right_index; + else + ++left_index; + } + throw NoSumNum{}; +} \ No newline at end of file diff --git a/task_01/src/find.hpp b/task_01/src/find.hpp new file mode 100644 index 0000000..8812e23 --- /dev/null +++ b/task_01/src/find.hpp @@ -0,0 +1,8 @@ +#include +#include + +struct NoSumNum { + std ::string s{"no possible way to solve task"}; +}; + +std ::vector FindNums(int k, std ::vector sequence); \ No newline at end of file diff --git a/task_01/src/main.cpp b/task_01/src/main.cpp index 0e4393b..9ec81e0 100644 --- a/task_01/src/main.cpp +++ b/task_01/src/main.cpp @@ -1,3 +1,3 @@ #include -int main() { return 0; } +int main() { return 0; } \ No newline at end of file diff --git a/task_01/src/test.cpp b/task_01/src/test.cpp index 87cef73..42dc3c1 100644 --- a/task_01/src/test.cpp +++ b/task_01/src/test.cpp @@ -1,5 +1,33 @@ #include -TEST(Test, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "find.hpp" + +TEST(FindNums, Simple) { + std ::vector seq{1, 2, 3, 4, 5}; + std ::vector ans{FindNums(5, seq)}; + ASSERT_EQ(5, ans[0] + ans[1]); +} + +TEST(FindNums, Negative) { + std ::vector seq{-100, -10, -9, -8, -1}; + std ::vector ans{FindNums(-9, seq)}; + ASSERT_EQ(-9, ans[0] + ans[1]); +} + +TEST(FindNums, WithZeros) { + std ::vector seq{ + -15, 0, 0, 2, 8, + }; + std ::vector ans{FindNums(10, seq)}; + ASSERT_EQ(10, ans[0] + ans[1]); +} + +TEST(FindNums, NoValue) { + std ::vector seq{0, 0, 2, 8, -15}; + EXPECT_THROW(FindNums(60, seq), NoSumNum); +} + +TEST(FindNums, Empty) { + std ::vector seq(0); + EXPECT_THROW(FindNums(60, seq), NoSumNum); } \ No newline at end of file diff --git a/task_02/src/stack.cpp b/task_02/src/stack.cpp deleted file mode 100644 index 8ca8990..0000000 --- a/task_02/src/stack.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "stack.hpp" - -#include - -void Stack::Push(int value) { data_.push(value); } - -int Stack::Pop() { - auto result = data_.top(); - data_.pop(); - return result; -} - -void MinStack::Push(int value) { data_.push_back(value); } - -int MinStack::Pop() { - auto result = data_.back(); - data_.pop_back(); - return result; -} - -int MinStack::GetMin() { return *std::min_element(data_.begin(), data_.end()); } \ No newline at end of file diff --git a/task_02/src/stack.hpp b/task_02/src/stack.hpp index 138ec40..fcf5a1b 100644 --- a/task_02/src/stack.hpp +++ b/task_02/src/stack.hpp @@ -1,23 +1,70 @@ -#pragma once - -#include +#include +#include #include +template +concept Comparable = requires(T a, T b) { + { a < b } -> std::convertible_to; +}; + +template class Stack { public: - void Push(int value); - int Pop(); + void Push(T k); + T Pop(); private: - std::stack data_; + std ::vector _data; }; +template +void Stack::Push(T k) { + _data.push_back(k); +} + +template +T Stack::Pop() { + if (_data.size() == 0) throw std::out_of_range("No data in stack"); + T pop_val{_data.back()}; + _data.pop_back(); + return pop_val; +} + +template class MinStack { public: - void Push(int value); - int Pop(); - int GetMin(); + void Push(T k); + T Pop(); + T GetMin(); private: - std::vector data_; + std ::vector _data; + std ::vector _min_data; }; + +template +void MinStack::Push(T k) { + if (_min_data.size() == 0) + _min_data.push_back(k); + else if (_min_data.back() > k) + _min_data.push_back(k); + else + _min_data.push_back(_min_data.back()); + _data.push_back(k); +} + +template +T MinStack::Pop() { + if ((_data.size() == 0) || (_min_data.size() == 0)) + throw std::out_of_range("No data in stack"); + T pop_val{_data.back()}; + _data.pop_back(); + _min_data.pop_back(); + return pop_val; +} + +template +T MinStack::GetMin() { + if (_min_data.size() == 0) throw std::out_of_range("No data in stack"); + return _min_data.back(); +} diff --git a/task_02/src/test.cpp b/task_02/src/test.cpp index 54e7ce9..f99f283 100644 --- a/task_02/src/test.cpp +++ b/task_02/src/test.cpp @@ -1,42 +1,66 @@ #include -#include - #include "stack.hpp" TEST(StackTest, Simple) { - Stack stack; - stack.Push(1); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - stack.Push(3); // Stack [1, 3] - ASSERT_EQ(stack.Pop(), 3); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] + Stack stack; + stack.Push(1); + ASSERT_EQ(stack.Pop(), 1); + stack.Push(1); + stack.Push(2); + ASSERT_EQ(stack.Pop(), 2); + ASSERT_EQ(stack.Pop(), 1); + stack.Push(1); + stack.Push(2); + ASSERT_EQ(stack.Pop(), 2); + stack.Push(3); + ASSERT_EQ(stack.Pop(), 3); + ASSERT_EQ(stack.Pop(), 1); } TEST(MinStackTest, Simple) { - MinStack stack; - stack.Push(1); // Stack [1] + MinStack stack; + stack.Push(1); ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] + ASSERT_EQ(stack.Pop(), 1); + stack.Push(1); + stack.Push(2); ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] - stack.Push(1); // Stack [1] - stack.Push(2); // Stack [1, 2] + ASSERT_EQ(stack.Pop(), 2); + ASSERT_EQ(stack.Pop(), 1); + stack.Push(1); + stack.Push(2); ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 2); // Stack [1] - stack.Push(3); // Stack [1, 3] + ASSERT_EQ(stack.Pop(), 2); + stack.Push(3); ASSERT_EQ(stack.GetMin(), 1); - ASSERT_EQ(stack.Pop(), 3); // Stack [1] - ASSERT_EQ(stack.Pop(), 1); // Stack [] + ASSERT_EQ(stack.Pop(), 3); + ASSERT_EQ(stack.Pop(), 1); +} + +TEST(Stack, Custom) { + Stack stack; + stack.Push(10); + ASSERT_EQ(10, stack.Pop()); + + EXPECT_THROW(stack.Pop(), std::out_of_range); +} + +TEST(MinStack, Custom) { + MinStack stack; + stack.Push(10); + stack.Push(2); + stack.Push(17); + ASSERT_EQ(2, stack.GetMin()); + + stack.Pop(); + stack.Pop(); + stack.Pop(); + EXPECT_THROW(stack.Pop(), std::out_of_range); + + stack.Push(10); + stack.Push(10); + stack.Push(10); + ASSERT_EQ(10, stack.GetMin()); } \ No newline at end of file diff --git a/task_03/src/main.cpp b/task_03/src/main.cpp index 0e4393b..a4fe526 100644 --- a/task_03/src/main.cpp +++ b/task_03/src/main.cpp @@ -1,3 +1,13 @@ #include -int main() { return 0; } +#include "warming_func.hpp" + +// void print(std::vector& v) { +// for (auto c : v) std ::cout << c << " "; +// } + +int main() { + // std ::vector s{5, 7, 9, 3, 4, 0, 2, -1, 3}; + // s = Warming(s); + // print(s); +} diff --git a/task_03/src/test.cpp b/task_03/src/test.cpp index ef5a86a..9b68bb4 100644 --- a/task_03/src/test.cpp +++ b/task_03/src/test.cpp @@ -1,8 +1,46 @@ #include -#include "topology_sort.hpp" +#include "warming_func.hpp" -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +TEST(Warm, Simple) { + std ::vector temperature = {73, 74, 75, 71, 69, 72, 76, 73}; + std ::vector ans = {1, 1, 4, 2, 1, 1, 0, 0}; + ASSERT_EQ(Warming(temperature), ans); +} + +TEST(Warm, Stable) { + std ::vector temperature = {30, 20, 10}; + std ::vector ans = {0, 0, 0}; + ASSERT_EQ(Warming(temperature), ans); +} + +TEST(Warm, OneDay) { + std ::vector temperature = {50}; + std ::vector ans = {0}; + ASSERT_EQ(Warming(temperature), ans); +} + +TEST(Warm, Empty) { + std ::vector temperature = {}; + std ::vector ans = {}; + ASSERT_EQ(Warming(temperature), ans); +} + +TEST(Warm, SameTemperature) { + std ::vector temperature = {10, 10, 10, 10}; + std ::vector ans = {0, 0, 0, 0}; + ASSERT_EQ(Warming(temperature), ans); +} + +TEST(Warm, Negative) { + std ::vector temperature = {-10, -5, -20}; + std ::vector ans = {1, 0, 0}; + ASSERT_EQ(Warming(temperature), ans); +} + +TEST(Warm, BigDiff) { + std ::vector temperature = {0, -10, 100, 5, 1000}; + std ::vector ans = {2, 1, 2, 1, 0}; + ASSERT_EQ(Warming(temperature), ans); } diff --git a/task_03/src/topology_sort.cpp b/task_03/src/topology_sort.cpp deleted file mode 100644 index e53f670..0000000 --- a/task_03/src/topology_sort.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "topology_sort.hpp" diff --git a/task_03/src/topology_sort.hpp b/task_03/src/topology_sort.hpp deleted file mode 100644 index 6f70f09..0000000 --- a/task_03/src/topology_sort.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/task_03/src/warming_func.cpp b/task_03/src/warming_func.cpp new file mode 100644 index 0000000..b1294ee --- /dev/null +++ b/task_03/src/warming_func.cpp @@ -0,0 +1,18 @@ +#include + +#include "warming_func.hpp" + +std ::vector Warming(std ::vector temperature) { + std::stack index; + std ::vector ans(temperature.size()); + + for (int i = 0; i < temperature.size(); ++i) { + while (!index.empty() && (temperature[i] > temperature[index.top()])) { + int j = index.top(); + index.pop(); + ans[j] = i - j; + } + index.push(i); + } + return ans; +} \ No newline at end of file diff --git a/task_03/src/warming_func.hpp b/task_03/src/warming_func.hpp new file mode 100644 index 0000000..a8020ee --- /dev/null +++ b/task_03/src/warming_func.hpp @@ -0,0 +1,3 @@ +#include + +std ::vector Warming(std ::vector temperature); diff --git a/task_04/src/EconomicCalculation.cpp b/task_04/src/EconomicCalculation.cpp new file mode 100644 index 0000000..4298014 --- /dev/null +++ b/task_04/src/EconomicCalculation.cpp @@ -0,0 +1,23 @@ +#include "EconomicCalculation.hpp" + +#include + +std::vector OptimizeFishPurchases(std::vector& prices, int K, int N) { + std::vector purchases(N, 0); + int CurrentDay = 0; + + while (CurrentDay < N) { + int Border = std::min(CurrentDay + K, N); + int BestDay = CurrentDay; + + for (int day = CurrentDay; day < Border; ++day) { + if (prices[day] < prices[BestDay]) { + BestDay = day; + } + } + int FishNeeded = Border - BestDay; + purchases[BestDay] += FishNeeded; + CurrentDay = BestDay + FishNeeded; + } + return purchases; +} \ No newline at end of file diff --git a/task_04/src/EconomicCalculation.hpp b/task_04/src/EconomicCalculation.hpp new file mode 100644 index 0000000..fcf53f7 --- /dev/null +++ b/task_04/src/EconomicCalculation.hpp @@ -0,0 +1,4 @@ +#include + +std::vector OptimizeFishPurchases(std::vector& prices, int N, + int K); \ No newline at end of file diff --git a/task_04/src/test.cpp b/task_04/src/test.cpp index 5e11617..1002a34 100644 --- a/task_04/src/test.cpp +++ b/task_04/src/test.cpp @@ -1,6 +1,58 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "EconomicCalculation.hpp" + +TEST(FindFish, Simple) { + std::vector prices = {3, 5, 2, 4, 1, 3}; + int K = 3; + int N = prices.size(); + auto result = OptimizeFishPurchases(prices, K, N); + std::vector expected = {0, 0, 1, 0, 2, 0}; + ASSERT_EQ(expected, result); +} + +TEST(FindFish, SamePrice) { + std::vector prices = {2, 2, 2, 2, 2}; + int K = 2; + int N = prices.size(); + auto result = OptimizeFishPurchases(prices, K, N); + std::vector expected = {2, 0, 2, 0, 1}; + ASSERT_EQ(expected, result); +} + +TEST(FindFish, ImmediateConsumption) { + std::vector prices = {5, 4, 3, 2, 1}; + int K = 1; + int N = prices.size(); + auto result = OptimizeFishPurchases(prices, K, N); + std::vector expected = {1, 1, 1, 1, 1}; + ASSERT_EQ(expected, result); } + +TEST(FindFish, OneBuy) { + std::vector prices = {5, 3, 4, 2, 6}; + int K = 10; + int N = prices.size(); + auto result = OptimizeFishPurchases(prices, K, N); + std::vector expected = {0, 0, 0, 2, 0}; + ASSERT_EQ(expected, result); +} + +TEST(FindFish, OneDay) { + std::vector prices = {3}; + int K = 5; + int N = prices.size(); + auto result = OptimizeFishPurchases(prices, K, N); + std::vector expected = {1}; + ASSERT_EQ(expected, result); +} + +TEST(FindFish, OptimizedBuy) { + std::vector prices = {5, 4, 3, 2, 1}; + int K = 3; + int N = prices.size(); + auto result = OptimizeFishPurchases(prices, K, N); + std::vector expected = {0, 0, 1, 0, 1}; + ASSERT_EQ(expected, result); +} \ No newline at end of file diff --git a/task_05/src/main.cpp b/task_05/src/main.cpp index 0e4393b..67c383e 100644 --- a/task_05/src/main.cpp +++ b/task_05/src/main.cpp @@ -1,3 +1,3 @@ -#include +#include "sorting.hpp" -int main() { return 0; } +int main() {} diff --git a/task_05/src/merge.cpp b/task_05/src/merge.cpp new file mode 100644 index 0000000..7e5b467 --- /dev/null +++ b/task_05/src/merge.cpp @@ -0,0 +1,26 @@ +#include + +#include "sorting.hpp" + +void MergeSort(std::vector& array) { + int n = array.size(); + std::vector buffer(n); + + for (int slice = 1; slice < n; slice *= 2) { + for (int left = 0; left < n; left += 2 * slice) { + int mid = std::min(left + slice, n); + int right = std::min(left + 2 * slice, n); + + int i = left, j = mid; + int k = left; + while (i < mid && j < right) { + buffer[k++] = array[i] <= array[j] ? array[i++] : array[j++]; + } + while (i < mid) buffer[k++] = array[i++]; + while (j < right) buffer[k++] = array[j++]; + + std::copy(buffer.begin() + left, buffer.begin() + right, + array.begin() + left); + } + } +} \ No newline at end of file diff --git a/task_05/src/sorting.hpp b/task_05/src/sorting.hpp new file mode 100644 index 0000000..f2e9c73 --- /dev/null +++ b/task_05/src/sorting.hpp @@ -0,0 +1,3 @@ +#include + +void MergeSort(std ::vector& array); \ No newline at end of file diff --git a/task_05/src/test.cpp b/task_05/src/test.cpp index 5e11617..64b6813 100644 --- a/task_05/src/test.cpp +++ b/task_05/src/test.cpp @@ -1,6 +1,52 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "sorting.hpp" + +TEST(MergeSort, Simple) { + std ::vector unsort{3, 2, 4, 5, 1, 9, 7}; + std ::vector sorted{1, 2, 3, 4, 5, 7, 9}; + MergeSort(unsort); + ASSERT_EQ(unsort, sorted); +} + +TEST(MergeSort, Simple2) { + std ::vector unsort{5, 7, 2, 3, 1, 6, 4}; + std ::vector sorted{1, 2, 3, 4, 5, 6, 7}; + MergeSort(unsort); + ASSERT_EQ(unsort, sorted); } + +TEST(MergeSort, Negative) { + std ::vector unsort{-5, -7, -2, -3, -1, -6, -4}; + std ::vector sorted{-7, -6, -5, -4, -3, -2, -1}; + MergeSort(unsort); + ASSERT_EQ(unsort, sorted); +} + +TEST(MergeSort, SameElements) { + std ::vector unsort{3, 3, 3, 3}; + std ::vector sorted{3, 3, 3, 3}; + MergeSort(unsort); + ASSERT_EQ(unsort, sorted); +} + +TEST(MergeSort, NoElements) { + std ::vector unsort{}; + std ::vector sorted{}; + MergeSort(unsort); + ASSERT_EQ(unsort, sorted); +} + +TEST(MergeSort, DiffElements) { + std ::vector unsort{1, -3, 5, 0, 0, -10, 6, 2, 21, -8, 90, -6}; + std ::vector sorted{-10, -8, -6, -3, 0, 0, 1, 2, 5, 6, 21, 90}; + MergeSort(unsort); + ASSERT_EQ(unsort, sorted); +} + +TEST(MergeSort, OneElement) { + std ::vector unsort{10}; + std ::vector sorted{10}; + MergeSort(unsort); + ASSERT_EQ(unsort, sorted); +} \ No newline at end of file diff --git a/task_06/src/NStatistic.cpp b/task_06/src/NStatistic.cpp new file mode 100644 index 0000000..0c96d68 --- /dev/null +++ b/task_06/src/NStatistic.cpp @@ -0,0 +1,12 @@ +#include "NStatistic.hpp" + +#include "../../lib/src/util.hpp" +#include + +int NStatistic(std ::vector data, int n) { + if (data.size() == 0) throw std::invalid_argument(""); + if (n > data.size()) throw std::invalid_argument(""); + + MergeSort(data); + return data[n]; +} \ No newline at end of file diff --git a/task_06/src/NStatistic.hpp b/task_06/src/NStatistic.hpp new file mode 100644 index 0000000..336d39f --- /dev/null +++ b/task_06/src/NStatistic.hpp @@ -0,0 +1,3 @@ +#include + +int NStatistic(std ::vector data, int n); \ No newline at end of file diff --git a/task_06/src/test.cpp b/task_06/src/test.cpp index 5e11617..4a3087f 100644 --- a/task_06/src/test.cpp +++ b/task_06/src/test.cpp @@ -1,6 +1,44 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "NStatistic.hpp" + +TEST(NStatistic, Simple) { + std ::vector data = {3, 1, 4, 1, 5}; + int n = 2; + int ans = 3; + ASSERT_EQ(NStatistic(data, n), ans); +} + +TEST(NStatistic, OneElem) { + std ::vector data = {100}; + int n = 0; + int ans = 100; + ASSERT_EQ(NStatistic(data, n), ans); +} + +TEST(NStatistic, SameElem) { + std ::vector data = {7, 7, 7, 7}; + int n = 2; + int ans = 7; + ASSERT_EQ(NStatistic(data, n), ans); +} + +TEST(NStatistic, NegativeElem) { + std ::vector data = {-5, 0, -1, 3, -2}; + int n = 2; + int ans = -1; + ASSERT_EQ(NStatistic(data, n), ans); +} + +TEST(NStatistic, BigN) { + std ::vector data = {1, 2, 3, 65, 4}; + int n = 100; + EXPECT_THROW(NStatistic(data, n), std::invalid_argument); +} + +TEST(NStatistic, Empty) { + std ::vector data = {}; + int n = 0; + EXPECT_THROW(NStatistic(data, n), std::invalid_argument); } diff --git a/task_07/CMakeLists.txt b/task_07/CMakeLists.txt index 91b6a60..68f94d9 100644 --- a/task_07/CMakeLists.txt +++ b/task_07/CMakeLists.txt @@ -24,11 +24,14 @@ add_executable(${PROJECT_NAME} ${source_list}) enable_testing() find_package(GTest REQUIRED) + + include_directories(${GTEST_INCLUDE_DIRS}) find_library(Utils ../) target_link_libraries(${PROJECT_NAME} PUBLIC Utils) + # Link runTests with what we want to test and the GTest and pthread library add_executable(${PROJECT_NAME}_tests ${test_source_list}) target_link_libraries( diff --git a/task_07/src/KDtree.cpp b/task_07/src/KDtree.cpp new file mode 100644 index 0000000..fd284f4 --- /dev/null +++ b/task_07/src/KDtree.cpp @@ -0,0 +1,96 @@ +#include "KDtree.hpp" + +#include + +#include +#include +#include + +void KDTree::PreparePoints(std::vector& points) { + std::sort(std::execution::par, points.begin(), points.end(), + [](const Point& a, const Point& b) { + return std::tie(a.x, a.y) < std::tie(b.x, b.y); + }); + + auto equal = [](const Point& a, const Point& b) { + return a.x == b.x && a.y == b.y; + }; + points.erase(std::unique(points.begin(), points.end(), equal), points.end()); +} + +void KDTree::Split(std::unique_ptr& node, Axis Ax, int depth) { + std::pair SAH = KDTree::SAH( + node->bounding_box.first, node->bounding_box.second, Ax, node->indices); + + double SAH_parant = Ci * (node->indices.second - node->indices.first); + + if (SAH.first >= SAH_parant) { + node->leaf = true; + return; + } + + node->left_child = std::make_unique(); + node->right_child = std::make_unique(); + + if (Ax == Axis::Ox) { + node->left_child->bounding_box.first = node->bounding_box.first; + node->left_child->bounding_box.second = + Point(SAH.second, node->bounding_box.second.y); + node->right_child->bounding_box.first = + Point(SAH.second, node->bounding_box.first.y); + node->right_child->bounding_box.second = node->bounding_box.second; + } else { + node->right_child->bounding_box.first = + Point(node->bounding_box.first.x, SAH.second); + node->right_child->bounding_box.second = node->bounding_box.second; + + node->left_child->bounding_box.first = node->bounding_box.first; + node->left_child->bounding_box.second = + Point(node->bounding_box.second.x, SAH.second); + } + + node->left_child->indices.first = node->indices.first; + + int left_count = std::count_if( + std::execution::par, cloud.begin() + node->indices.first, + cloud.begin() + node->indices.second + 1, + [Ax, split_pos = SAH.second](const Point& p) { + return (Ax == Axis::Ox) ? p.x < split_pos : p.y < split_pos; + }); + + node->left_child->indices.second = node->indices.first + left_count - 1; + node->right_child->indices.first = node->indices.first + left_count; + node->right_child->indices.second = node->indices.second; + + Ax = (Ax == Axis::Ox) ? Axis::Oy : Axis::Ox; + + if (depth < max_parallel_depth) { +#pragma omp task shared(node) + Split(node->left_child, Ax, depth + 1); + +#pragma omp task shared(node) + Split(node->right_child, Ax, depth + 1); + +#pragma omp taskwait + } else { + Split(node->left_child, Ax, depth + 1); + Split(node->right_child, Ax, depth + 1); + } +} + +KDTree::KDTree(std ::vector points) { + if (points.empty()) throw std::invalid_argument{"No Points detected"}; + + cloud = std::move(points); + PreparePoints(cloud); + + root = std::make_unique(); + root->indices = std::make_pair(0, cloud.size() - 1); + root->bounding_box = std::make_pair(cloud[0], cloud[cloud.size() - 1]); + +#pragma omp parallel + { +#pragma omp single nowait + Split(root, Axis::Ox, 0); + } +} diff --git a/task_07/src/KDtree.hpp b/task_07/src/KDtree.hpp new file mode 100644 index 0000000..4297920 --- /dev/null +++ b/task_07/src/KDtree.hpp @@ -0,0 +1,64 @@ +#ifndef KDtreeHpp +#define KDtreeHpp + +#include +#include + +#include "constants.hpp" + +struct Point { + double x; + double y; + Point(double x, double y) : x{x}, y{y} {} + Point() : x{NONE}, y{NONE} {} + + bool operator==(const Point& other) const { + constexpr double epsilon = 1e-9; + return (std::abs(x - other.x) < epsilon) && + (std::abs(y - other.y) < epsilon); + } +}; + +class KDTree { + public: + KDTree(std::vector points); + ~KDTree() = default; + Point NearestPoint(Point target); + + private: + std ::vector cloud; + + struct Node { + bool leaf = false; + std::unique_ptr left_child = nullptr; + std::unique_ptr right_child = nullptr; + std::pair bounding_box = + std::make_pair(Point(0, 0), Point(0, 0)); + std ::pair indices; // промежуток точек + // принадлежащих данной bounding_box [от, до] + }; + std::unique_ptr root; + enum class Axis { + Ox = 0, + Oy = 1, + }; + + void Split(std::unique_ptr& node, Axis Ax = Axis::Ox, int depth = 0); + std ::pair SAH(Point left_min_point, Point right_max_point, + Axis curr_Axis, std::pair& range); + std::pair FindMinimum(Point target, + std::unique_ptr& node); + void PreparePoints(std::vector& points); + double Distance(Point first, Point second); + double DistanceToBox(Point& point, std::pair& box); + bool IntoBox(Point target, std::pair box); + + template + auto GetAxis(const T& request, Axis ax) { + if (ax == Axis::Ox) + return request.x; + else + return request.y; + } +}; +#endif \ No newline at end of file diff --git a/task_07/src/SAH.cpp b/task_07/src/SAH.cpp new file mode 100644 index 0000000..d661765 --- /dev/null +++ b/task_07/src/SAH.cpp @@ -0,0 +1,55 @@ +#include + +#include + +#include "KDtree.hpp" +#include "constants.hpp" + +std::pair KDTree::SAH(Point left_min_point, + Point right_max_point, Axis curr_axis, + std::pair& range) { + std::pair SAH_result{NONE, NONE}; + double width = + GetAxis(right_max_point, curr_axis) - GetAxis(left_min_point, curr_axis); + double width_x = right_max_point.x - left_min_point.x; + double width_y = right_max_point.y - left_min_point.y; + double width_w = curr_axis == Axis::Ox ? width_y : width_x; + double SApar = width_x * width_y; + + if (SApar <= 0) return SAH_result; + + const int bins = PARITION; + std::vector binCounts(bins, 0); + + double bin_width = width / bins; + if (bin_width <= 0) return SAH_result; + + for (int index = range.first; index <= range.second; ++index) { + int bin_index = static_cast((GetAxis(cloud[index], curr_axis) - + GetAxis(left_min_point, curr_axis)) / + bin_width); + bin_index = std::clamp(bin_index, 0, bins - 1); + ++binCounts[bin_index]; + } + + std::vector prefix_sum(bins + 1, 0); + for (int i = 1; i <= bins; ++i) { + prefix_sum[i] = prefix_sum[i - 1] + binCounts[i - 1]; + } + + for (int i = 1; i < bins; ++i) { + double x0 = GetAxis(left_min_point, curr_axis) + width * i / bins; + double SAl = (x0 - GetAxis(left_min_point, curr_axis)) * width_w; + double SAr = (GetAxis(right_max_point, curr_axis) - x0) * width_w; + + int Nl = prefix_sum[i]; + int Nr = (range.second - range.first + 1) - Nl; + + double SAH = Ct + Ci * (SAl * Nl + SAr * Nr) / SApar; + if ((SAH < SAH_result.first) || (SAH_result.first < 0)) { + SAH_result = std::make_pair(SAH, x0); + } + } + + return SAH_result; +} \ No newline at end of file diff --git a/task_07/src/constants.hpp b/task_07/src/constants.hpp new file mode 100644 index 0000000..ca6ee32 --- /dev/null +++ b/task_07/src/constants.hpp @@ -0,0 +1,11 @@ +#ifndef CONSTS +#define CONSTS +#include +// SAH +constexpr double Ct{1}; // стоимость прослеживания луча внутри узла +constexpr double Ci{1}; // стоимость пересечения (плоскостью) лучом +constexpr double PARITION{33}; // разбиение по оси + +constexpr double NONE{std::numeric_limits::max()}; +constexpr int max_parallel_depth{4}; +#endif \ No newline at end of file diff --git a/task_07/src/main.cpp b/task_07/src/main.cpp index 0e4393b..87affd0 100644 --- a/task_07/src/main.cpp +++ b/task_07/src/main.cpp @@ -1,3 +1,16 @@ #include -int main() { return 0; } +#include "KDtree.hpp" +#include "vector" + +int main() { + std::vector cloud = { + Point(1.0, 2.0), Point(3.0, 4.0), Point(5.0, 6.0), + Point(7.0, 8.0), Point(9.0, 10.0), + }; + + KDTree tree(cloud); + std ::cout << "compiled\n"; + Point k = tree.NearestPoint(Point(4.8, 5.9)); + std ::cout << k.x << " " << k.y << '\n'; +} diff --git a/task_07/src/min_search.cpp b/task_07/src/min_search.cpp new file mode 100644 index 0000000..eccfa07 --- /dev/null +++ b/task_07/src/min_search.cpp @@ -0,0 +1,59 @@ +#include + +#include "KDtree.hpp" + +double KDTree::Distance(Point first, Point second) { + return ((first.x - second.x) * (first.x - second.x) + + (first.y - second.y) * (first.y - second.y)); +} + +bool KDTree::IntoBox(Point target, std::pair box) { + if ((target.x >= box.first.x) && (target.x <= box.second.x)) { + if ((target.y >= box.first.y) && (target.y <= box.second.y)) return true; + } + return false; +} + +double KDTree::DistanceToBox(Point& point, std::pair& box) { + double dx = std::max({box.first.x - point.x, 0.0, point.x - box.second.x}); + double dy = std::max({box.first.y - point.y, 0.0, point.y - box.second.y}); + return dx * dx + dy * dy; +} + +std::pair KDTree::FindMinimum(Point target, + std::unique_ptr& node) { + if (node->leaf) { + double min_dist = NONE; + Point NearestPoint; + for (int i = node->indices.first; i <= node->indices.second; ++i) { + double current_dist = Distance(cloud[i], target); + if (current_dist < min_dist) { + min_dist = current_dist; + NearestPoint = cloud[i]; + } + } + return {min_dist, NearestPoint}; + } + + bool target_in_left = IntoBox(target, node->left_child->bounding_box); + auto& first_child = target_in_left ? node->left_child : node->right_child; + auto& second_child = target_in_left ? node->right_child : node->left_child; + + auto [min_dist, nearest] = FindMinimum(target, first_child); + + double dist_to_second_box = DistanceToBox(target, second_child->bounding_box); + if (dist_to_second_box < min_dist) { + auto [second_dist, second_nearest] = FindMinimum(target, second_child); + if (second_dist < min_dist) { + min_dist = second_dist; + nearest = second_nearest; + } + } + + return {min_dist, nearest}; +} + +Point KDTree::NearestPoint(Point target) { + auto point = FindMinimum(target, root); + return point.second; +} \ No newline at end of file diff --git a/task_07/src/test.cpp b/task_07/src/test.cpp index 5e11617..89d3cae 100644 --- a/task_07/src/test.cpp +++ b/task_07/src/test.cpp @@ -1,6 +1,124 @@ #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include +#include +#include + +#include "KDtree.hpp" + +std::vector GenerateRandomPoints(size_t count, double min = 0.0, + double max = 1000.0) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution dist(min, max); + + std::vector points; + points.reserve(count); + for (size_t i = 0; i < count; ++i) { + points.emplace_back(dist(gen), dist(gen)); + } + return points; +} + +TEST(KD3, Simple) { + std::vector cloud = { + Point(1.0, 2.0), Point(3.0, 4.0), Point(5.0, 6.0), + Point(7.0, 8.0), Point(9.0, 10.0), + }; + + KDTree tree(cloud); + + Point k = tree.NearestPoint(Point(4.8, 5.9)); + ASSERT_EQ(k, Point(5.0, 6.0)); +} + +TEST(KD3, SameDistanse) { + std::vector cloud = { + Point(0.0, 0.0), Point(1.0, 0.0), Point(0.0, 1.0), + Point(-1.0, 0.0), Point(0.0, -1.0), + }; + + KDTree tree(cloud); + + Point k = tree.NearestPoint(Point(0.0, 0.0)); + ASSERT_EQ(k, Point(0.0, 0.0)); +} + +TEST(KD3, OneLine) { + std::vector cloud = { + Point(1.0, 1.0), Point(1.0, 2.0), Point(1.0, 3.0), + Point(1.0, 4.0), Point(1.0, 5.0), + }; + + KDTree tree(cloud); + + Point k = tree.NearestPoint(Point(1.2, 3.1)); + ASSERT_EQ(k, Point(1.0, 3.0)); +} + +TEST(KD3, Dublicates) { + std::vector cloud = { + Point(2.0, 2.0), Point(2.0, 2.0), Point(3.0, 3.0), + Point(2.0, 2.0), Point(4.0, 4.0), + }; + + KDTree tree(cloud); + + Point k = tree.NearestPoint(Point(2.1, 2.1)); + ASSERT_EQ(k, Point(2.0, 2.0)); +} + +TEST(KD3, Error) { + std::vector cloud(0); + EXPECT_THROW(KDTree tree(cloud), std::invalid_argument); +} + +TEST(KD3, TimeTest_1000) { + auto cloud = GenerateRandomPoints(1000); + + auto start = std::chrono::high_resolution_clock::now(); + KDTree tree(cloud); + auto end = std::chrono::high_resolution_clock::now(); + + auto duration = + std::chrono::duration_cast(end - start); + EXPECT_TRUE(duration.count() < 500); +} + +TEST(KD3, TimeTest_10000) { + auto cloud = GenerateRandomPoints(10000); + + auto start = std::chrono::high_resolution_clock::now(); + KDTree tree(cloud); + auto end = std::chrono::high_resolution_clock::now(); + + auto duration = + std::chrono::duration_cast(end - start); + EXPECT_TRUE(duration.count() < 500); } + +TEST(KD3, TimeTest_1M) { + auto cloud = GenerateRandomPoints(1000000); + + auto start = std::chrono::high_resolution_clock::now(); + KDTree tree(cloud); + auto end = std::chrono::high_resolution_clock::now(); + + auto duration = + std::chrono::duration_cast(end - start); + EXPECT_TRUE(duration.count() < 5000); +} + +TEST(KD3, TimeTest_10M) { + auto cloud = GenerateRandomPoints(10'000'000); + + KDTree tree(cloud); + auto start = std::chrono::high_resolution_clock::now(); + + tree.NearestPoint(Point(3.75, 2.1)); + auto end = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(end - start); + EXPECT_TRUE(duration.count() < 20000); +} \ No newline at end of file diff --git a/task_08/src/HashTable.cpp b/task_08/src/HashTable.cpp new file mode 100644 index 0000000..b58109b --- /dev/null +++ b/task_08/src/HashTable.cpp @@ -0,0 +1,70 @@ +#include "HashTable.hpp" + +#include +#include + +size_t HashTable::MyHash(const std::string& value) { + return std::hash{}(value) * 0xdeadbeef; +} + +HashTable::HashTable() { + std::vector PreparedData(13, ZeroElem); + data = std::move(PreparedData); +} + +void HashTable::Resize() { + std::vector NewData(data.size() * 2, ZeroElem); + std::vector OldData = std::move(data); + data = std::move(NewData); + for (auto& elem : OldData) { + if (elem.CurrentLabel == Label::Full) { + add(elem.Key, elem.Value); + } + } +} + +void HashTable::add(const std::string& key, int value) { + int index = MyHash(key) % data.size(); + int BeginingIndex = index; + while ((data[index].CurrentLabel != Label::Empty) && + (data[index].CurrentLabel != Label::Deleted)) { + if (data[index].CurrentLabel == Label::Full && data[index].Key == key) { + data[index].Value = value; + return; + } + ++index; + if (index >= data.size()) index = 0; + if (index == BeginingIndex) break; + } + data[index].Value = value; + data[index].Key = key; + data[index].CurrentLabel = Label::Full; + ++EngagedSpace; + if (EngagedSpace > (data.size() / 2)) Resize(); +} + +void HashTable::remove(const std::string& key) { + int index = MyHash(key) % data.size(); + int BeginingIndex = index; + while (data[index].Key != key) { + ++index; + if (index >= data.size()) index = 0; + if (index == BeginingIndex) throw std::runtime_error("ValueError"); + } + data[index].CurrentLabel = Label::Deleted; + --EngagedSpace; +} + +int HashTable::get(const std::string& key) { + int index = MyHash(key) % data.size(); + while ((data[index].Key != key) && + (data[index].CurrentLabel != Label::Empty)) { + ++index; + if (index >= data.size()) index = 0; + } + if (data[index].CurrentLabel == Label::Empty) { + throw std::runtime_error("ValueError"); + } else { + return data[index].Value; + } +} \ No newline at end of file diff --git a/task_08/src/HashTable.hpp b/task_08/src/HashTable.hpp new file mode 100644 index 0000000..2934db2 --- /dev/null +++ b/task_08/src/HashTable.hpp @@ -0,0 +1,28 @@ +#include +#include + +class HashTable { + public: + HashTable(); + + void add(const std::string& key, int value); + void remove(const std::string& key); + int get(const std::string& key); + + private: + enum struct Label { + Empty = 0, + Full = 1, + Deleted = 2, + }; + struct Elem { + Label CurrentLabel; + int Value; + std::string Key; + }; + int EngagedSpace = 0; + std ::vector data; + size_t MyHash(const std::string& value); + void Resize(); + Elem ZeroElem = {Label::Empty, 0}; +}; \ No newline at end of file diff --git a/task_08/src/main.cpp b/task_08/src/main.cpp index 0e4393b..3d180c4 100644 --- a/task_08/src/main.cpp +++ b/task_08/src/main.cpp @@ -1,3 +1,3 @@ -#include +#include "HashTable.hpp" -int main() { return 0; } +int main() {} \ No newline at end of file diff --git a/task_08/src/test.cpp b/task_08/src/test.cpp index 5e11617..2e62a39 100644 --- a/task_08/src/test.cpp +++ b/task_08/src/test.cpp @@ -1,6 +1,86 @@ - #include -TEST(TopologySort, Simple) { - ASSERT_EQ(1, 1); // Stack [] +#include "HashTable.hpp" + +TEST(HashTable, Simple) { + HashTable table; + table.add("first", 1); + table.add("second", 2); + ASSERT_EQ(table.get("first"), 1); +} + +TEST(HashTable, DeleteTest) { + HashTable table; + table.add("first", 1); + table.add("second", 2); + table.add("second_full", 3); + table.remove("second"); + ASSERT_EQ(table.get("second_full"), 3); } + +TEST(HashTable, FalseDelete) { + HashTable table; + table.add("first", 1); + table.add("second", 2); + EXPECT_THROW(table.remove("no_second"), std::runtime_error); +} + +TEST(HashTable, FalseGet) { + HashTable table; + table.add("first", 1); + table.add("second", 2); + EXPECT_THROW(table.get("no_second"), std::runtime_error); +} + +TEST(HashTable, ResizeTest1) { + HashTable table; + table.add("1", -8); + table.add("2", 2); + table.add("3", 1); + table.add("4", 2); + table.add("5", 1); + table.add("5", 2); + table.add("6", 1); + table.add("7", 2); + table.add("8", 1); + table.add("9", 2); + table.add("10", 1); + table.add("11", 2); + table.add("12", 1); + table.add("13", 2); + table.add("14", 1); + table.add("15", 2); + table.add("16", 1); + table.add("17", 2); + ASSERT_EQ(table.get("1"), -8); +} + +TEST(HashTable, ResizeTest2) { + HashTable table; + table.add("1", -8); + table.add("2", 2); + table.add("3", 1); + table.add("4", 2); + table.add("5", 1); + table.add("5", 2); + table.add("6", 1); + table.add("7", 2); + table.add("8", 1); + table.add("9", 2); + table.add("10", 1); + table.add("11", 2); + table.add("12", 1); + table.add("13", 2); + table.add("14", 1); + table.add("15", 2); + table.add("16", 1); + table.add("17", 19); + ASSERT_EQ(table.get("17"), 19); +} + +TEST(HashTable, AddSameKey) { + HashTable table; + table.add("first", 1); + table.add("first", 2); + ASSERT_EQ(table.get("first"), 2); +} \ No newline at end of file diff --git a/task_09/src/TableTask.cpp b/task_09/src/TableTask.cpp new file mode 100644 index 0000000..a38818e --- /dev/null +++ b/task_09/src/TableTask.cpp @@ -0,0 +1,45 @@ +#include "TableTask.hpp" + +std::vector TaskSolve(int n, int m, int k, + std::vector>& table, + std::vector>& queries) { + std::vector answer; + std::vector> IsGood(n - 1, std::vector(m)); + + for (int j = 0; j < m; ++j) { + for (int i = 0; i < n - 1; ++i) { + IsGood[i][j] = (table[i][j] <= table[i + 1][j]); + } + } + + std::vector> prefix(m, std::vector(n)); + for (int j = 0; j < m; ++j) { + prefix[j][0] = 0; + for (int i = 1; i < n; ++i) { + prefix[j][i] = prefix[j][i - 1] + (IsGood[i - 1][j] ? 1 : 0); + } + } + + for (auto& query : queries) { + int l = query.first - 1; + int r = query.second - 1; + + if (l == r) { + answer.push_back("Yes"); + continue; + } + + bool found = false; + for (int j = 0; j < m; ++j) { + int cnt = prefix[j][r] - prefix[j][l]; + if (cnt == r - l) { + found = true; + break; + } + } + + answer.push_back(found ? "Yes" : "No"); + } + + return answer; +} \ No newline at end of file diff --git a/task_09/src/TableTask.hpp b/task_09/src/TableTask.hpp new file mode 100644 index 0000000..932fad5 --- /dev/null +++ b/task_09/src/TableTask.hpp @@ -0,0 +1,6 @@ +#include +#include + +std::vector TaskSolve(int n, int m, int k, + std::vector>& table, + std::vector>& queries); \ No newline at end of file diff --git a/task_09/src/test.cpp b/task_09/src/test.cpp index a42caa4..f9479cd 100644 --- a/task_09/src/test.cpp +++ b/task_09/src/test.cpp @@ -1,23 +1,54 @@ #include -#include +#include "TableTask.hpp" + +TEST(CanReachNonDecreasingSegment, SampleTest) { + std::vector> table = { + {1, 2, 3, 5}, {3, 1, 3, 2}, {4, 5, 2, 3}, {5, 5, 3, 2}, {4, 4, 3, 4}}; + + std::vector> queries = {{1, 1}, {2, 5}, {4, 5}, + {3, 5}, {1, 3}, {1, 5}}; + + auto result = TaskSolve(5, 4, 6, table, queries); + std::vector expected = {"Yes", "No", "Yes", "Yes", "Yes", "No"}; + + ASSERT_EQ(result, expected); +} TEST(CanReachNonDecreasingSegment, 1) { - // ASSERT_EQ(SolveFunction(5, 4, 6, - // std::vector>{{1, 2, 3, 5}, - // {3, 1, 3, 2}, - // {4, 5, 2, 3}, - // {5, 5, 3, 2}, - // {4, 4, 3, 4}}, - // std::vector>{ - // {1, 1}, {2, 5}, {4, 5}, {3, 5}, {1, 3}, {1, - // 5}}), - // (std::vector{"Yes", "No", "Yes", "Yes", "Yes", - // "No"})); + std::vector> table = { + {1, 2, 3, 5}, {3, 1, 3, 2}, {4, 5, 2, 3}, {5, 5, 3, 2}, {4, 4, 3, 4}}; + std::vector> queries{{1, 1}, {2, 5}, {4, 5}, + {3, 5}, {1, 3}, {1, 5}}; + ASSERT_EQ(TaskSolve(5, 4, 6, table, queries), + (std::vector{"Yes", "No", "Yes", "Yes", "Yes", "No"})); } TEST(CanReachNonDecreasingSegment, 2) { - // ASSERT_EQ(SolveFunction(1, 1, 1, std::vector>{{1, 1}}, - // std::vector>{{1, 1}}), - // (std::vector{"Yes"})); + std::vector> table = {{1, 1}}; + std::vector> queries = {{1, 1}}; + ASSERT_EQ(TaskSolve(1, 1, 1, table, queries), + (std::vector{"Yes"})); } + +TEST(CanReachNonDecreasingSegment, SingleElement) { + std::vector> table = {{1}}; + std::vector> queries{{1, 1}}; + ASSERT_EQ(TaskSolve(1, 1, 1, table, queries), + (std::vector{"Yes"})); +} + +TEST(CanReachNonDecreasingSegment, AllColumnsSorted) { + std::vector> table = {{1, 1, 1}, {2, 2, 2}, {3, 3, 3}}; + std::vector> queries{{1, 3}, {2, 3}, {1, 2}}; + ASSERT_EQ(TaskSolve(3, 3, 3, table, queries), + (std::vector{"Yes", "Yes", "Yes"})); +} + +TEST(CanReachNonDecreasingSegment, OneColumnSorted) { + std::vector> table = { + {5, 1}, {4, 2}, {3, 3}, {2, 4}, {1, 5}}; + std::vector> queries{{1, 5}, {2, 4}, {3, 5}}; + ASSERT_EQ(TaskSolve(5, 2, 3, table, queries), + (std::vector{"Yes", "Yes", "Yes"})); +} \ No newline at end of file