├── 2 ├── 2_3.cpp ├── 2_1-3.cpp ├── 2_2.cpp ├── 2_1_insertion_sort.cpp ├── 2_1-4.cpp ├── 2_3-7.cpp ├── 2_2-2.cpp ├── 2_3-5.cpp ├── 2_3_merge_sort.cpp └── 2_4.cpp ├── 4 ├── 4.2-7.cpp ├── 4-4.cpp ├── 4.1-5.cpp └── 4-5.cpp ├── 5 ├── 5.2-3.cpp ├── 5.3-3.cpp ├── 5.3-6.cpp ├── 5.3-2.cpp ├── 5.3-4.cpp ├── 5.3-1.cpp ├── 5.1-2.cpp ├── 5.1-3.cpp ├── 5.2-4.cpp ├── 5.3-7.cpp ├── 5.3-5.cpp ├── 5.4.2_balls_and_bins.cpp ├── 5.2_hiring_problem.cpp ├── 5.4.3_streaks.cpp ├── 5.4-4.cpp ├── 5.4.1_the_birthday_paradox.cpp ├── 5-1.cpp ├── 5.4.4_online_hiring_problem.cpp └── 5.4-6.cpp ├── 6 ├── 6.3_building_a_heap.cpp ├── 6.2-2.cpp ├── 6.2-5.cpp └── 6.4_the_heapsort_algorithm.cpp ├── 7 ├── 7.2-2.cpp ├── 7.1_description_of_quicksort.cpp ├── 7.1-4.cpp ├── 7.2-3.cpp ├── 7.1-2.cpp ├── 7-1_hoare_partition.cpp ├── 7-2.cpp ├── 7-4.cpp ├── 7.3_a_randomized_version_of_quicksort.cpp ├── 7.2-6.cpp └── 7.4-6.cpp ├── 8 ├── 8.2-3.cpp ├── 8.2-4.cpp ├── 8.2_counting_sort.cpp ├── 8-2.cpp ├── 8-5-d.cpp ├── 8-4.cpp ├── 8.4-4.cpp └── 8.3_radix_sort.cpp ├── 9 ├── 9.3-9.cpp ├── 9.3-4.cpp ├── 9.1_minimum_and_maximum.cpp ├── 9.3-7.cpp ├── 9.3-3.cpp ├── 9.3-5.cpp ├── 9.3-8.cpp ├── 9-3.cpp ├── 9.1-1.cpp ├── 9.2_selection_in_expected_linear_time.cpp ├── 9.2-3.cpp └── 9-1.cpp ├── 10 ├── 10.2-2.cpp ├── 10.2-1.cpp ├── 10.2-3.cpp ├── 10.1-7.cpp ├── 10.1-6.cpp ├── 10.4-6.cpp ├── 10-3.cpp ├── 10.3-2.cpp ├── 10.1-2.cpp ├── 10.3_implementing_pointers_and_objects.cpp ├── 10.1-4.cpp ├── 10.4-2.cpp ├── 10.1_stacks_and_queues.cpp ├── 10.4-3.cpp ├── 10.2-5.cpp ├── 10.3-5.cpp ├── 10.2_linked_lists.cpp ├── 10.2-4.cpp ├── 10.4-4.cpp ├── 10.2_linked_lists_2.cpp ├── 10.3-4.cpp └── 10.1-5.cpp ├── 11 └── 11.1-4.cpp ├── 12 ├── 12.1-4_.cpp ├── 12.1-4.cpp ├── 12.1_what_is_binary_search_tree.cpp ├── 12.1-3.cpp └── 12-2.cpp ├── 14 └── 14-2_1.cpp ├── 15 ├── 15.1-5.cpp ├── 15.1-3.cpp ├── 15-12.cpp ├── 15-10.cpp ├── 15-9.cpp ├── 15.1-4.cpp ├── 15.4-4.cpp ├── 15-11.cpp ├── 15.4-5_6.cpp ├── 15.4-3.cpp ├── 15.5_optimal_binary_search_tree.cpp ├── 15-3.cpp ├── 15.4-2.cpp └── 15.4_longest_common_subsequence.cpp ├── 16 ├── 16-1_a.cpp ├── 16-2_a.cpp ├── 16.5-2.cpp ├── 16.3_Huffman_codes.cpp ├── 16.2-7.cpp ├── 16.3-7.cpp ├── 16.2-5.cpp ├── 16.1-2.cpp ├── 16-1_d.cpp ├── 16.2-6.cpp ├── 16-2_b.cpp ├── 16.1-1.cpp ├── 16.1-4.cpp ├── 16.1-5.cpp ├── 16-3_b.cpp └── 16.1_an_activity_selection_problem.cpp ├── 17 ├── 17-1_b.cpp ├── 17.1_aggregate_analysis_incrementing_binary_counter.cpp ├── 17-1_a.cpp ├── 17.4_dynamic_table.cpp └── 17.1_aggregate_analysis_stack_operation.cpp ├── 21 ├── 21.2-1.cpp ├── 21.3_disjoint_set_forests.cpp ├── 21.3-2.cpp └── 21-2.cpp ├── 22 ├── 22.1-4.cpp ├── 22.1-6.cpp ├── 22.1-1.cpp ├── 22.4_topological_sort.cpp ├── 22.1-3.cpp ├── 22.4-2.cpp ├── 22.4-5.cpp ├── 22.3_depth_first_search.cpp ├── 22.1-5.cpp ├── 22.2-9.cpp ├── 22.4-3.cpp ├── 22.2-8.cpp ├── 22.3-7.cpp ├── 22.2_breadth_first_search.cpp ├── 22.3-10.cpp └── 22.3-13.cpp ├── 27 ├── 27-1.cpp ├── 27.1_the_basics_of_dynamic_multithreading.cpp └── 27-6_d.cpp ├── 30 ├── 30.1-2.cpp ├── 30.2_the_DFT_and_FFT.cpp └── 30.1-5.cpp ├── 31 ├── 31.2-4.cpp ├── 31.2-8.cpp ├── 31.1-12.cpp ├── 31.6_powers_of_an_element.cpp ├── 31.2_greatest_common_divisor.cpp ├── 31-4_b.cpp ├── 31.9_integer_factorization.cpp ├── 31-1.cpp ├── 31.6-2.cpp ├── 31.9-4.cpp ├── 31.4_solving_modular_linear_equations.cpp ├── 31-4_d.cpp ├── 31.1-13.cpp └── 31.1-8.cpp ├── 32 ├── 32.1-4.cpp ├── 32.1_the_naive_string_matching_algorithm.cpp ├── 32.1-2.cpp └── 32.4-7.cpp ├── 34 ├── 34-2_a.cpp └── 34.5-4.cpp ├── 35 ├── 35-1.cpp ├── 35-5.cpp └── 35.4-2.cpp └── README.md /README.md: -------------------------------------------------------------------------------- 1 | # CLRS 2 | 3 | C++ implementation of CLRS 3/e example codes and exercise for studying purpose. 4 | Non-coding involved exercises will not be shared. 5 | 6 | For CLRS 4/e, visit https://github.com/frozenca/CLRS (incomplete) 7 | -------------------------------------------------------------------------------- /14/14-2_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::vector Josephus(size_t n, size_t m) { 5 | assert(m && n && n >= m); 6 | std::vector res; 7 | for (size_t i = 0; i < n; i++) { 8 | res.push_back(m * (i + 1) % n); 9 | } 10 | return res; 11 | } 12 | 13 | int main() { 14 | 15 | } -------------------------------------------------------------------------------- /31/31.2-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::size_t IterativeEuclid(std::size_t a, std::size_t b) { 6 | while (b) { 7 | auto r = a % b; 8 | std::tie(a, b) = std::tie(b, r); 9 | } 10 | return a; 11 | } 12 | 13 | int main() { 14 | std::cout << IterativeEuclid(38, 16); 15 | 16 | } -------------------------------------------------------------------------------- /16/16-1_a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::tuple coinChange(size_t n) { 5 | auto q = n / 25; 6 | n -= q * 25; 7 | auto d = n / 10; 8 | n -= d * 10; 9 | auto k = n / 5; 10 | n -= k * 5; 11 | auto p = n; 12 | return {q, d, k, p}; 13 | } 14 | 15 | int main() { 16 | } 17 | -------------------------------------------------------------------------------- /10/10.2-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | void Push(std::forward_list& l, const T& key) { 7 | l.push_front(key); 8 | } 9 | 10 | template 11 | T Pop(std::forward_list& l) { 12 | T x = l.front(); 13 | l.pop_front(); 14 | } 15 | 16 | int main() { 17 | 18 | } -------------------------------------------------------------------------------- /15/15.1-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | size_t fibonacci(size_t n) { 6 | if (n <= 1) { 7 | return 1; 8 | } 9 | std::vector f (n + 1); 10 | f[0] = 1; 11 | f[1] = 1; 12 | for (size_t i = 2; i <= n; i++) { 13 | f[i] = f[i - 1] + f[i - 2]; 14 | } 15 | return f[n]; 16 | } 17 | 18 | int main() { 19 | std::cout << fibonacci(23); 20 | } -------------------------------------------------------------------------------- /10/10.2-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | void Insert(std::forward_list& l, const T& key) { 7 | l.push_front(key); 8 | } 9 | 10 | template 11 | void Delete(std::forward_list& l, typename std::forward_list::iterator it) { 12 | auto it2 = it; 13 | ++it2; 14 | *it = *it2; 15 | l.erase_after(it); 16 | } 17 | 18 | int main() { 19 | 20 | } -------------------------------------------------------------------------------- /2/2_3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | T horner(const std::vector& A, T x) { 7 | T value = 0; 8 | for (size_t i = 0; i < A.size(); i++) { 9 | value = A[i] + x * value; 10 | } 11 | return value; 12 | } 13 | 14 | int main() { 15 | std::vector coefficients {1, -2, 1}; 16 | std::cout << horner(coefficients, 1.0) << '\n'; 17 | std::cout << horner(coefficients, 2.0) << '\n'; 18 | } -------------------------------------------------------------------------------- /5/5.2-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::mt19937 gen(std::random_device{}()); 6 | 7 | int main() { 8 | constexpr size_t trials = 1000; 9 | size_t sum = 0; 10 | std::uniform_int_distribution<> dice(1, 6); 11 | 12 | for (size_t i = 0; i < trials; i++) { 13 | sum += dice(gen); 14 | } 15 | 16 | std::cout << "sum / trials of a dice : " << static_cast(sum) / static_cast(trials) << '\n'; 17 | 18 | } -------------------------------------------------------------------------------- /2/2_1-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | std::optional linearSearch(std::vector& A, const T& key) { 8 | for (size_t i = 0; i < A.size(); i++) { 9 | if (A[i] == key) { 10 | return i; 11 | } 12 | } 13 | return {}; 14 | } 15 | 16 | int main() { 17 | std::vector v {5, 2, 3, 1, 4}; 18 | assert(linearSearch(v, 3)); 19 | assert(!linearSearch(v, 6)); 20 | } -------------------------------------------------------------------------------- /4/4.2-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std::complex_literals; 4 | 5 | int main() { 6 | std::complex z1 = 1. + 2i; 7 | std::complex z2 = 3. + 4i; 8 | int a = z1.real(); 9 | int b = z1.imag(); 10 | int c = z2.real(); 11 | int d = z2.imag(); 12 | int ac = a * c; 13 | int bd = b * d; 14 | int a_bc_d = (a + b) * (c + d); 15 | std::complex z3 = (ac - bd) * 1.0 + (a_bc_d - (ac - bd)) * 1.0 * 1i; 16 | assert(z1 * z2 == z3); 17 | 18 | } -------------------------------------------------------------------------------- /31/31.2-8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::size_t LCM(const std::vector& A) { 7 | if (A.empty()) { 8 | return 1; 9 | } 10 | auto x = A[0]; 11 | auto g = A[0]; 12 | for (std::size_t i = 1; i < A.size(); i++) { 13 | x *= A[i]; 14 | g = std::gcd(g, A[i]); 15 | } 16 | return x / g; 17 | } 18 | 19 | int main() { 20 | std::vector v {6, 7, 20, 14, 9}; 21 | std::cout << LCM(v); 22 | 23 | } -------------------------------------------------------------------------------- /16/16-2_a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | std::vector minimizeAverageCompletion(std::vector>& tasks) { 10 | sr::sort(tasks); 11 | std::vector taskOrder; 12 | taskOrder.reserve(tasks.size()); 13 | for (const auto& [task, index] : tasks) { 14 | taskOrder.push_back(index); 15 | } 16 | return taskOrder; 17 | } 18 | 19 | 20 | int main() { 21 | } 22 | -------------------------------------------------------------------------------- /5/5.3-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | constexpr size_t N = 20; 10 | std::vector v (N); 11 | std::mt19937 gen(std::random_device{}()); 12 | std::iota(v.begin(), v.end(), 1); 13 | std::uniform_int_distribution<> dist(0, N - 1); 14 | for (size_t i = 0; i < N; i++) { 15 | std::swap(v[i], v[dist(gen)]); 16 | } 17 | for (auto n : v) { 18 | std::cout << n << ' '; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /10/10.2-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct ForwardList { 7 | std::forward_list data; 8 | std::forward_list::iterator it; 9 | 10 | ForwardList() {it = data.begin();} 11 | 12 | void Enqueue(const T& x) { 13 | data.insert_after(it); 14 | auto it2 = it; 15 | ++it2; 16 | it = it2; 17 | } 18 | 19 | void Dequeue() { 20 | data.pop_front(); 21 | } 22 | }; 23 | 24 | 25 | 26 | 27 | int main() { 28 | 29 | } -------------------------------------------------------------------------------- /5/5.3-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | constexpr size_t N = 20; 10 | std::vector v (N); 11 | std::mt19937 gen(std::random_device{}()); 12 | std::iota(v.begin(), v.end(), 0); 13 | for (size_t i = 0; i < N; i++) { 14 | std::uniform_int_distribution<> dist(i, N - 1); 15 | std::swap(v[i], v[dist(gen)]); 16 | } 17 | 18 | for (auto n : v) { 19 | std::cout << n << ' '; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /16/16.5-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace sr = std::ranges; 7 | 8 | bool isIndependent(std::vector& A) { 9 | assert(sr::all_of(A, [&A](auto n) {return n < A.size();})); 10 | size_t n = A.size(); 11 | std::vector B (n + 1); 12 | for (auto k : A) { 13 | B[k]++; 14 | } 15 | for (size_t i = 0; i <= n; i++) { 16 | B[i + 1] += B[i]; 17 | if (B[i + 1] > i) return false; 18 | } 19 | return true; 20 | } 21 | 22 | int main() { 23 | } 24 | -------------------------------------------------------------------------------- /17/17-1_b.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::size_t bitReversedIncrement(std::size_t i) { 10 | std::size_t m = 1u << 7u; 11 | while (m & i) { 12 | i ^= m; 13 | m >>= 1u; 14 | } 15 | m |= i; 16 | return m; 17 | } 18 | 19 | int main() { 20 | std::size_t i = 0; 21 | for (std::size_t j = 0; j < 255; j++) { 22 | std::cout << i << ' '; 23 | i = bitReversedIncrement(i); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /9/9.3-9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sr = std::ranges; 9 | 10 | double findOptimalPlace(std::vector>& A) { 11 | auto compY = [](auto& p1, auto& p2) {return p1.second < p2.second;}; 12 | sr::nth_element(A, A.begin() + A.size() / 2, compY); 13 | return A[A.size() / 2].second; 14 | } 15 | 16 | int main() { 17 | std::vector> A {{1, 3}, {2, 5}, {3, 1}, {4, 2}, {5, 4}}; 18 | std::cout << findOptimalPlace(A); 19 | 20 | } -------------------------------------------------------------------------------- /9/9.3-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sr = std::ranges; 9 | 10 | int main() { 11 | std::vector v {4, 2, 1, 5, 3, 6}; 12 | sr::nth_element(v, v.begin() + v.size() / 2); 13 | std::cout << "Smaller elements: "; 14 | for (size_t i = 0; i < v.size() / 2; i++) { 15 | std::cout << v[i] << ' '; 16 | } 17 | std::cout << "\nLarger elements: "; 18 | for (size_t i = v.size() / 2 + 1; i < v.size(); i++) { 19 | std::cout << v[i] << ' '; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /16/16.3_Huffman_codes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | std::priority_queue Huffman(const std::vector& C) { 8 | assert(!C.empty()); 9 | size_t n = C.size(); 10 | std::priority_queue, std::greater> Q (C.begin(), C.end()); 11 | for (size_t i = 0; i < n - 1; i++) { 12 | auto x = Q.top(); 13 | Q.pop(); 14 | auto y = Q.top(); 15 | Q.pop(); 16 | auto z = x + y; 17 | Q.push(z); 18 | } 19 | return Q; 20 | } 21 | 22 | int main() { 23 | } 24 | -------------------------------------------------------------------------------- /10/10.1-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct Stack { 9 | std::queue A; 10 | std::queue B; 11 | 12 | void Push(const T& x) { 13 | A.push(x); 14 | } 15 | 16 | T Pop() { 17 | while (A.size() > 1) { 18 | T x = A.front(); 19 | A.pop(); 20 | B.push(x); 21 | } 22 | T x = A.front(); 23 | A.pop(); 24 | std::swap(A, B); 25 | return x; 26 | } 27 | }; 28 | 29 | 30 | int main() { 31 | 32 | } -------------------------------------------------------------------------------- /16/16.2-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | size_t maximizePayoff(std::vector& A, std::vector& B) { 10 | assert(sr::all_of(A, [](auto n) {return n > 0;})); 11 | assert(sr::all_of(B, [](auto n) {return n > 0;})); 12 | assert(A.size() == B.size()); 13 | sr::sort(A); 14 | sr::sort(B); 15 | size_t prod = 1; 16 | for (size_t i = 0; i < A.size(); i++) { 17 | prod *= std::pow(A[i], B[i]); 18 | } 19 | return prod; 20 | } 21 | 22 | int main() { 23 | } 24 | -------------------------------------------------------------------------------- /5/5.3-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | constexpr size_t N = 20; 10 | std::vector v (N); 11 | std::mt19937 gen(std::random_device{}()); 12 | std::iota(v.begin(), v.end(), 1); 13 | std::uniform_int_distribution<> dist(0, N - 1); 14 | for (size_t i = 0; i < N - 1; i++) { 15 | std::uniform_int_distribution<> dist_local(i + 1, N - 1); 16 | std::swap(v[i], v[dist_local(gen)]); 17 | } 18 | for (auto n : v) { 19 | std::cout << n << ' '; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /10/10.1-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct Queue { 8 | std::stack A; 9 | std::stack B; 10 | 11 | void Enqueue(const T& x) { 12 | A.push(x); 13 | } 14 | 15 | T Dequeue() { 16 | if (B.empty()) { 17 | while (!A.empty()) { 18 | T x = A.top(); 19 | A.pop(); 20 | B.push(x); 21 | } 22 | } 23 | T x = B.top(); 24 | B.pop(); 25 | return x; 26 | } 27 | }; 28 | 29 | 30 | int main() { 31 | 32 | } -------------------------------------------------------------------------------- /2/2_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template > 7 | void bubbleSort(std::vector& A, Comp comp = Comp()) { 8 | for (size_t i = 0; i < A.size() - 1; i++) { 9 | for (size_t j = A.size() - 1; j > i; j--) { 10 | if (comp(A[j], A[j - 1])) { 11 | std::swap(A[j], A[j - 1]); 12 | } 13 | } 14 | } 15 | } 16 | 17 | int main() { 18 | std::vector v {2, 1, 7, 6, 3, 5}; 19 | bubbleSort(v); 20 | for (auto n : v) { 21 | std::cout << n << ' '; 22 | } 23 | } -------------------------------------------------------------------------------- /5/5.3-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | constexpr size_t N = 20; 10 | std::vector v (N); 11 | std::mt19937 gen(std::random_device{}()); 12 | std::iota(v.begin(), v.end(), 1); 13 | std::uniform_int_distribution<> dist(0, N - 1); 14 | auto u = v; 15 | auto offset = dist(gen); 16 | for (size_t i = 0; i < N; i++) { 17 | auto dst = (i + offset) % N; 18 | u[dst] = v[i]; 19 | } 20 | for (auto n : u) { 21 | std::cout << n << ' '; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /9/9.1_minimum_and_maximum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | T minimum(const std::vector& A) { 6 | T minValue = A[0]; 7 | for (size_t i = 1; i < A.size(); i++) { 8 | if (minValue > A[i]) { 9 | minValue = A[i]; 10 | } 11 | } 12 | return minValue; 13 | } 14 | 15 | template 16 | T maximum(const std::vector& A) { 17 | T maxValue = A[0]; 18 | for (size_t i = 1; i < A.size(); i++) { 19 | if (maxValue < A[i]) { 20 | maxValue = A[i]; 21 | } 22 | } 23 | return maxValue; 24 | } 25 | 26 | int main() { 27 | 28 | } -------------------------------------------------------------------------------- /2/2_1_insertion_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template > 6 | void insertionSort(std::vector& A, Comp comp = Comp()) { 7 | for (size_t j = 1; j < A.size(); j++) { 8 | T key = A[j]; 9 | size_t i = j - 1; 10 | while (i < A.size() && comp(A[i], key)) { 11 | A[i + 1] = A[i]; 12 | i--; 13 | } 14 | A[i + 1] = key; 15 | } 16 | } 17 | 18 | int main() { 19 | std::vector v {5, 2, 3, 1, 4}; 20 | insertionSort(v); 21 | for (auto n : v) { 22 | std::cout << n << ' '; 23 | } 24 | } -------------------------------------------------------------------------------- /5/5.3-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | constexpr size_t N = 20; 10 | std::vector v (N); 11 | std::mt19937 gen(std::random_device{}()); 12 | std::iota(v.begin(), v.end(), 1); 13 | std::uniform_int_distribution<> dist(0, N - 1); 14 | std::swap(v[0], v[dist(gen)]); 15 | for (size_t i = 1; i < N; i++) { 16 | std::uniform_int_distribution<> dist_local(i, N - 1); 17 | std::swap(v[i], v[dist_local(gen)]); 18 | } 19 | for (auto n : v) { 20 | std::cout << n << ' '; 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /2/2_1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | std::bitset add(const std::bitset& A, const std::bitset& B) { 8 | std::bitset C; 9 | int carry = 0; 10 | for (size_t j = 0; j < N; j++) { 11 | auto temp = A[j] + B[j] + carry; 12 | C[j] = temp % 2; 13 | carry = temp / 2; 14 | } 15 | C[N] = carry; 16 | return C; 17 | } 18 | 19 | 20 | int main() { 21 | size_t a = 37; 22 | size_t b = 26; 23 | std::bitset<8> A(a); 24 | std::bitset<8> B(b); 25 | auto C = add(A, B); 26 | assert(C.to_ulong() == a + b); 27 | } -------------------------------------------------------------------------------- /5/5.1-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::mt19937 gen(std::random_device{}()); 6 | std::bernoulli_distribution dist(0.5); 7 | 8 | int RANDOM(int a, int b) { 9 | if (a > b) { 10 | return RANDOM(b, a); 11 | } 12 | if (a == b) { 13 | return a; 14 | } 15 | double m = a + (b - a) / 2.0; 16 | int r = dist(gen); 17 | if (r) { 18 | return RANDOM(std::ceil(m), b); 19 | } else { 20 | return RANDOM(a, std::floor(m)); 21 | } 22 | } 23 | 24 | int main() { 25 | for (size_t i = 0; i < 30; i++) { 26 | std::cout << RANDOM(8, 13) << ' '; 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /16/16.3-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | std::priority_queue HuffmanTernary(const std::vector& C) { 8 | assert(!C.empty()); 9 | size_t n = C.size(); 10 | std::priority_queue, std::greater> Q (C.begin(), C.end()); 11 | for (size_t i = 0; i < (n - 1) / 2; i++) { 12 | auto x = Q.top(); 13 | Q.pop(); 14 | auto y = Q.top(); 15 | Q.pop(); 16 | auto z = Q.top(); 17 | Q.pop(); 18 | auto w = x + y + z; 19 | Q.push(w); 20 | } 21 | return Q; 22 | } 23 | 24 | int main() { 25 | } 26 | -------------------------------------------------------------------------------- /31/31.1-12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::pair Division(std::size_t a, std::size_t b) { 8 | assert(a > b && b > 0); 9 | std::size_t p = 0; 10 | while (a >= b) { 11 | auto w_diff = std::bit_width(a) - std::bit_width(b); 12 | a -= (b << w_diff); 13 | p += (1 << w_diff); 14 | } 15 | return {p, a}; 16 | } 17 | 18 | int main() { 19 | auto a = 1373267; 20 | auto b = 2293; 21 | auto [p, q] = Division(a, b); 22 | std::cout << p << ' ' << q << '\n'; 23 | std::cout << a / b << ' ' << a % b << '\n'; 24 | 25 | 26 | } -------------------------------------------------------------------------------- /5/5.1-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::mt19937 gen(std::random_device{}()); 5 | std::bernoulli_distribution BIASED_RANDOM(0.8); 6 | 7 | bool UNBIASED_RANDOM() { 8 | while (true) { 9 | bool a = BIASED_RANDOM(gen); 10 | bool b = BIASED_RANDOM(gen); 11 | if (a != b) { 12 | return a; 13 | } 14 | } 15 | } 16 | 17 | int main() { 18 | 19 | size_t count = 0; 20 | size_t trials = 100000; 21 | for (size_t i = 0; i < trials; i++) { 22 | if (UNBIASED_RANDOM()) { 23 | count++; 24 | } 25 | } 26 | std::cout << static_cast(count) / static_cast(trials) << '\n'; 27 | } -------------------------------------------------------------------------------- /15/15.1-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int ModifiedCutRod(const std::vector& p, size_t n, int c) { 9 | std::vector r (n + 1); 10 | for (size_t j = 1; j <= n; j++) { 11 | int q = p[j]; 12 | for (size_t i = 1; i < j; i++) { 13 | q = std::max(q, p[i] + r[j - i] - c); 14 | } 15 | r[j] = q; 16 | } 17 | return r[n]; 18 | } 19 | 20 | int main() { 21 | std::vector p {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30}; 22 | std::cout << ModifiedCutRod(p, 10, 0) << '\n'; 23 | std::cout << ModifiedCutRod(p, 10, 4) << '\n'; 24 | 25 | } -------------------------------------------------------------------------------- /31/31.6_powers_of_an_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::size_t ModularExponentiation(std::size_t a, std::size_t b, std::size_t n) { 9 | assert(n); 10 | std::size_t c = 0; 11 | std::size_t d = 1; 12 | auto k = std::bit_width(b); 13 | std::bitset<64> B(b); 14 | for (std::size_t i = k - 1; i < k; i--) { 15 | c *= 2; 16 | d = (d * d) % n; 17 | if (B[i]) { 18 | c++; 19 | d = (d * a) % n; 20 | } 21 | } 22 | return d; 23 | } 24 | 25 | int main() { 26 | std::cout << ModularExponentiation(7, 560, 561); 27 | 28 | } -------------------------------------------------------------------------------- /16/16.2-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | std::vector> unitIntervals(std::vector& points) { 10 | sr::sort(points); 11 | std::vector> intvs; 12 | auto start = points[0]; 13 | intvs.emplace_back(start, start + 1.0); 14 | for (auto point : points) { 15 | if (point <= start + 1.0) { 16 | continue; 17 | } else { 18 | start = point; 19 | intvs.emplace_back(start, start + 1.0); 20 | } 21 | } 22 | return intvs; 23 | } 24 | 25 | int main() { 26 | } 27 | -------------------------------------------------------------------------------- /31/31.2_greatest_common_divisor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::size_t Euclid(std::size_t a, std::size_t b) { 6 | if (!b) { 7 | return a; 8 | } else { 9 | return Euclid(b, a % b); 10 | } 11 | } 12 | 13 | std::tuple ExtendedEuclid(std::size_t a, std::size_t b) { 14 | if (!b) { 15 | return {a, 1, 0}; 16 | } else { 17 | auto [d_, x_, y_] = ExtendedEuclid(b, a % b); 18 | std::size_t d = d_; 19 | int x = y_; 20 | int y = x_ - static_cast(a / b) * y_; 21 | return {d, x, y}; 22 | } 23 | } 24 | 25 | int main() { 26 | assert(Euclid(30, 21) == 3); 27 | 28 | } -------------------------------------------------------------------------------- /10/10.4-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct NaryTreeNode { 8 | T key; 9 | NaryTreeNode* left_child; 10 | NaryTreeNode* right_sibling; 11 | bool is_rightmost = false; 12 | 13 | NaryTreeNode(const T& key) : key {key} {} 14 | 15 | NaryTreeNode* parent() { 16 | auto curr = this; 17 | while (!curr->is_rightmost) { 18 | curr = curr->right_sibling; 19 | } 20 | return curr->right_sibling; 21 | } 22 | }; 23 | 24 | template 25 | struct NaryTree { 26 | std::unique_ptr> root; 27 | }; 28 | 29 | int main() { 30 | 31 | } -------------------------------------------------------------------------------- /2/2_3-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | bool twoSum(std::vector& A, const T& key) { 8 | std::sort(A.begin(), A.end()); 9 | size_t left = 0, right = A.size() - 1; 10 | while (left < right) { 11 | if (A[left] + A[right] < key) { 12 | left++; 13 | } else if (A[left] + A[right] > key) { 14 | right--; 15 | } else { 16 | return true; 17 | } 18 | } 19 | return false; 20 | } 21 | 22 | int main() { 23 | std::vector v {1, 2, 4, 6, 7}; 24 | assert(twoSum(v, 11)); 25 | assert(!twoSum(v, 20)); 26 | assert(!twoSum(v, 2)); 27 | } -------------------------------------------------------------------------------- /8/8.2-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace sr = std::ranges; 7 | 8 | std::vector countingSort(std::vector& A, size_t k) { 9 | assert(*sr::max_element(A) <= k); 10 | std::vector B (A.size()); 11 | std::vector C (k + 1); 12 | for (auto n : A) { 13 | C[n]++; 14 | } 15 | for (size_t j = 1; j <= k; j++) { 16 | C[j] += C[j - 1]; 17 | } 18 | for (auto n : A) { 19 | B[C[n]] = n; 20 | C[n]--; 21 | } 22 | return B; 23 | } 24 | 25 | int main() { 26 | std::vector v {3, 2, 6, 1, 5, 4}; 27 | v = countingSort(v, 6); 28 | assert(sr::is_sorted(v)); 29 | } -------------------------------------------------------------------------------- /10/10-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::mt19937 gen(std::random_device{}()); 6 | 7 | template 8 | size_t compactListSearch(const std::vector& A, const T& k) { 9 | size_t i = 0; 10 | std::uniform_int_distribution<> dist(0, A.size() - 1); 11 | while (i < A.size() && A[i] < k) { 12 | size_t j = dist(gen); 13 | if (A[i] < A[j] && A[j] <= k) { 14 | i = j; 15 | if (A[i] == k) { 16 | return i; 17 | } 18 | } 19 | i++; 20 | } 21 | if (i >= A.size() || A[i] > k) { 22 | return -1; 23 | } else { 24 | return i; 25 | } 26 | } 27 | 28 | int main() { 29 | 30 | } -------------------------------------------------------------------------------- /8/8.2-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::mt19937 gen(std::random_device{}()); 8 | 9 | int main() { 10 | constexpr size_t N = 100; 11 | constexpr size_t k = 10; 12 | 13 | std::uniform_int_distribution<> dist(0, k); 14 | std::vector v (N); 15 | for (auto& n : v) { 16 | n = dist(gen); 17 | } 18 | 19 | std::vector B (v.size()); 20 | std::vector C (k + 1); 21 | for (auto n : v) { 22 | C[n]++; 23 | } 24 | for (size_t j = 1; j <= k; j++) { 25 | C[j] += C[j - 1]; 26 | } 27 | 28 | std::cout << "Integers in [3, 5] : " << C[5] - C[2] << '\n'; 29 | 30 | } -------------------------------------------------------------------------------- /2/2_2-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | void selectionSort(std::vector& A) { 9 | for (size_t i = 0; i < A.size() - 1; i++) { 10 | T min_value = A[i]; 11 | size_t argmax = i; 12 | for (size_t j = i + 1; j < A.size(); j++) { 13 | if (min_value > A[j]) { 14 | min_value = A[j]; 15 | argmax = j; 16 | } 17 | } 18 | std::swap(A[i], A[argmax]); 19 | } 20 | } 21 | 22 | int main() { 23 | std::vector v {5, 2, 3, 1, 4}; 24 | selectionSort(v); 25 | for (auto n : v) { 26 | std::cout << n << ' '; 27 | } 28 | } -------------------------------------------------------------------------------- /11/11.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Dictionary { 6 | std::array T; 7 | std::array S; 8 | size_t topS = 0; 9 | 10 | size_t Search(size_t k) { 11 | if (1 <= T[k] && T[k] <= topS && S[T[k]] == k) { 12 | return S[T[k]]; 13 | } else { 14 | return -1; 15 | } 16 | } 17 | 18 | void Insert(size_t k) { 19 | S[topS] = k; 20 | T[k] = topS; 21 | topS++; 22 | } 23 | 24 | void Delete(size_t k) { 25 | S[T[k]] = S[topS]; 26 | T[S[T[k]]] = T[k]; 27 | T[k] = -1; 28 | topS--; 29 | } 30 | 31 | }; 32 | 33 | int main() { 34 | 35 | } -------------------------------------------------------------------------------- /16/16.1-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | std::vector> GreedyActivitySelector(std::vector>& intervals) { 10 | sr::sort(intervals, [](auto& a, auto& b) {return a.second < b.second;}); 11 | size_t n = intervals.size(); 12 | std::vector> A; 13 | A.push_back(intervals.back()); 14 | size_t k = n - 1; 15 | for (size_t m = n - 2; m < n; m--) { 16 | if (intervals[m].second <= intervals[k].first) { 17 | A.push_back(intervals[m]); 18 | k = m; 19 | } 20 | } 21 | return A; 22 | } 23 | 24 | int main() { 25 | } 26 | -------------------------------------------------------------------------------- /16/16-1_d.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::pair, std::vector> computeChange(size_t n, const std::vector& d, 7 | size_t k) { 8 | std::vector c (n + 1); 9 | std::vector denom (n + 1); 10 | for (size_t j = 1; j <= n; j++) { 11 | c[j] = std::numeric_limits::max(); 12 | for (size_t i = 1; i <= k; i++) { 13 | if (j > d[i] && 1 + c[j - d[i]] < c[j]) { 14 | c[j] = 1 + c[j - d[i]]; 15 | denom[j] = d[i]; 16 | } 17 | } 18 | } 19 | return {c, denom}; 20 | } 21 | 22 | int main() { 23 | } 24 | -------------------------------------------------------------------------------- /8/8.2_counting_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace sr = std::ranges; 7 | 8 | std::vector countingSort(std::vector& A, size_t k) { 9 | assert(*sr::max_element(A) <= k); 10 | std::vector B (A.size()); 11 | std::vector C (k + 1); 12 | for (auto n : A) { 13 | C[n]++; 14 | } 15 | for (size_t j = 1; j <= k; j++) { 16 | C[j] += C[j - 1]; 17 | } 18 | for (size_t j = A.size() - 1; j < A.size(); j--) { 19 | B[C[A[j]] - 1] = A[j]; 20 | C[A[j]]--; 21 | } 22 | return B; 23 | } 24 | 25 | int main() { 26 | std::vector v {3, 2, 6, 1, 5, 4}; 27 | v = countingSort(v, 6); 28 | assert(sr::is_sorted(v)); 29 | } -------------------------------------------------------------------------------- /34/34-2_a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::pair DivideEvenly(std::size_t n_x, std::size_t x, 6 | std::size_t n_y, std::size_t y) { 7 | std::size_t total = n_x * x + n_y * y; 8 | if (total % 2 == 1) { 9 | return {0, 0}; 10 | } 11 | std::size_t half = total / 2; 12 | for (std::size_t i = 1; i <= n_x; i++) { 13 | for (std::size_t j = 1; j <= n_y; j++) { 14 | if (i * x + j * y == half) { 15 | return {i, j}; 16 | } 17 | } 18 | } 19 | return {0, 0}; 20 | } 21 | 22 | int main() { 23 | auto [b_x, b_y] = DivideEvenly(4, 7, 6, 13); 24 | std::cout << b_x << ' ' << b_y << '\n'; 25 | 26 | } -------------------------------------------------------------------------------- /30/30.1-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | std::pair, T> LongDivision(const std::vector& A, const T& x_0) { 9 | assert(!A.empty()); 10 | auto A_ = A; 11 | std::size_t n = A.size(); 12 | std::vector q (n - 1); 13 | for (std::size_t k = n - 2; k < n; k--) { 14 | q[k] = A_[k + 1]; 15 | A_[k] += x_0 * A_[k + 1]; 16 | } 17 | auto r = A_[0]; 18 | return {q, r}; 19 | } 20 | 21 | int main() { 22 | std::vector A {-4, 0, -2, 1}; 23 | auto [q, r] = LongDivision(A, 3.0); 24 | for (auto q_ : q) { 25 | std::cout << q_ << ' '; 26 | } 27 | std::cout << '\n'; 28 | std::cout << r << '\n'; 29 | 30 | 31 | } -------------------------------------------------------------------------------- /15/15-12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using Player = std::pair; // (cost, vorp) 8 | 9 | double Baseball(size_t N, size_t X, const std::vector>& players) { 10 | std::vector> f (N + 1, std::vector(X + 1)); 11 | for (size_t i = 1; i <= N; i++) { 12 | for (size_t j = 0; j <= X; j++) { 13 | f[i][j] = f[i - 1][j]; // don't sign 14 | for (const auto& [cost, vorp] : players[i]) { 15 | if (j >= cost) { 16 | f[i][j] = std::max(f[i][j], f[i - 1][j - cost] + vorp); // sign 17 | } 18 | } 19 | } 20 | } 21 | return f[N][X]; 22 | } 23 | 24 | int main() { 25 | 26 | } -------------------------------------------------------------------------------- /17/17.1_aggregate_analysis_incrementing_binary_counter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace crn = std::chrono; 7 | 8 | void Increment(std::vector& A) { 9 | std::size_t i = 0; 10 | while (i < A.size() - 1 && A[i] == 1) { 11 | A[i] = 0; 12 | i++; 13 | } 14 | if (i < A.size() - 1) { 15 | A[i] = 1; 16 | } 17 | } 18 | 19 | int main() { 20 | constexpr std::size_t SZ = 100'000; 21 | std::vector v (100'000); 22 | auto t1 = crn::steady_clock::now(); 23 | for (std::size_t i = 0; i < SZ; i++) { 24 | Increment(v); 25 | } 26 | auto t2 = crn::steady_clock::now(); 27 | auto d1 = crn::duration_cast(t2 - t1); 28 | std::cout << d1.count() << "ms\n"; 29 | 30 | } -------------------------------------------------------------------------------- /22/22.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | class Graph { 7 | std::vector> adj; 8 | public: 9 | Graph() : adj(n) {} 10 | 11 | [[nodiscard]] Graph getReduced() const { 12 | Graph reduced; 13 | 14 | for (std::size_t i = 0; i < n; i++) { 15 | std::vector aux (n); 16 | for (auto neighbor : adj[i]) { 17 | if (neighbor != i) { 18 | if (aux[neighbor] != 1) { 19 | aux[neighbor] = 1; 20 | reduced.adj[i].push_back(neighbor); 21 | } 22 | } 23 | } 24 | } 25 | return reduced; 26 | } 27 | }; 28 | 29 | 30 | int main() { 31 | 32 | } 33 | -------------------------------------------------------------------------------- /32/32.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool GapMatching(const std::string& T, const std::string& P, 7 | const char delimeter = ' ', std::size_t t = 0, std::size_t p = 0) { 8 | if (p == P.length()) { 9 | return t <= T.length(); 10 | } 11 | if (t == T.length()) { 12 | return false; 13 | } 14 | if (T[t] == P[p]) { 15 | if (p + 1 < P.length() && P[p + 1] == delimeter) { 16 | return GapMatching(T, P, delimeter, t + 1, p + 2); 17 | } else { 18 | return GapMatching(T, P, delimeter, t + 1, p + 1); 19 | } 20 | } else { 21 | return GapMatching(T, P, delimeter, t + 1, p); 22 | } 23 | } 24 | 25 | int main() { 26 | assert(GapMatching("cabccbacbacab", "ab ba c")); 27 | } -------------------------------------------------------------------------------- /4/4-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const double phi = (1.0 + std::sqrt(5.0)) / 2.0; 6 | 7 | size_t fibonacciRec(size_t n, std::vector& cache) { 8 | if (!cache[n - 1]) { 9 | cache[n - 1] = fibonacciRec(n - 1, cache) + fibonacciRec(n - 2, cache); 10 | } 11 | return cache[n - 1]; 12 | } 13 | 14 | size_t fibonacci(size_t n) { 15 | if (n <= 2) return 1; 16 | std::vector cache(n); 17 | cache[0] = 1; 18 | cache[1] = 1; 19 | return fibonacciRec(n, cache); 20 | } 21 | 22 | size_t fibonacci2(size_t n) { 23 | double phi_n = std::pow(phi, n); 24 | return static_cast(phi_n / std::sqrt(5.0)); 25 | } 26 | 27 | int main() { 28 | for (size_t i = 0; i < 30; i++) { 29 | assert(fibonacci(i) == fibonacci2(i)); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /31/31-4_b.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::size_t ModularExponentiation(std::size_t a, std::size_t b, std::size_t n) { 9 | assert(n); 10 | std::size_t c = 0; 11 | std::size_t d = 1; 12 | auto k = std::bit_width(b); 13 | std::bitset<64> B(b); 14 | for (std::size_t i = k - 1; i < k; i--) { 15 | c *= 2; 16 | d = (d * d) % n; 17 | if (B[i]) { 18 | c++; 19 | d = (d * a) % n; 20 | } 21 | } 22 | return d; 23 | } 24 | 25 | bool isQuadraticResidue(std::size_t a, std::size_t p) { 26 | return ModularExponentiation(a, (p - 1) >> 1, p) == 1; 27 | } 28 | 29 | int main() { 30 | assert(isQuadraticResidue(4, 7)); 31 | assert(!isQuadraticResidue(3, 7)); 32 | 33 | } -------------------------------------------------------------------------------- /22/22.1-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | class GraphMatrix { 7 | std::array adj; 8 | public: 9 | [[nodiscard]] bool hasUniversalSink() const { 10 | std::size_t i = 0; 11 | std::size_t j = 0; 12 | while (i < n && j < n) { 13 | if (adj[i * n + j] == 0) { 14 | j++; 15 | } else { 16 | i++; 17 | } 18 | } 19 | if (i == n) { 20 | return false; 21 | } else { 22 | for (std::size_t k = 0; k < n; k++) { 23 | if (k != i && adj[i * n + k] == 0) { 24 | return false; 25 | } 26 | } 27 | } 28 | return true; 29 | } 30 | }; 31 | 32 | int main() { 33 | 34 | } 35 | -------------------------------------------------------------------------------- /21/21.2-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct ListSet { 6 | std::list> l; 7 | }; 8 | 9 | template 10 | using Element = std::pair&>; 11 | 12 | template 13 | ListSet MakeSet(const T& key) { 14 | ListSet ls; 15 | ls.l.emplace_back(key, ls); 16 | return ls; 17 | } 18 | 19 | template 20 | ListSet FindSet(const Element& elm) { 21 | return elm.second; 22 | } 23 | 24 | template 25 | ListSet Union(ListSet& ls1, ListSet& ls2) { 26 | if (ls1.l.size() < ls2.l.size()) { 27 | std::swap(ls1.l, ls2.l); 28 | } 29 | for (auto& [elm, refr] : ls2.l) { 30 | refr = ls1; 31 | } 32 | ls1.l.splice(ls1.l.end(), ls2.l); 33 | return ls1; 34 | } 35 | 36 | int main() { 37 | 38 | } -------------------------------------------------------------------------------- /15/15-10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | double Invest(double d, size_t yr, size_t n, const std::vector>& r, double f_1, double f_2) { 7 | std::vector I (yr + 1); 8 | std::vector R (yr + 1); 9 | for (size_t k = yr - 1; k < yr; k--) { 10 | size_t q = 0; 11 | for (size_t i = 0; i < n; i++) { 12 | if (r[i][k] > r[q][k]) { 13 | q = i; 14 | } 15 | } 16 | if (R[k + 1] + d * r[I[k + 1]][k] - f_1 > R[k + 1] + d * r[q][k] - f_2) { 17 | R[k] = R[k + 1] + d * r[I[k + 1]][k] - f_1; 18 | I[k] = I[k + 1]; 19 | } else { 20 | R[k] = R[k + 1] + d * r[q][k] - f_2; 21 | I[k] = q; 22 | } 23 | } 24 | return R[0]; 25 | } 26 | 27 | int main() { 28 | 29 | } -------------------------------------------------------------------------------- /22/22.1-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Graph { 4 | std::size_t n; 5 | std::vector> adj; 6 | public: 7 | explicit Graph(std::size_t n) : n {n}, adj(n) {} 8 | 9 | [[nodiscard]] std::vector getOutdegrees() const { 10 | std::vector outdegrees(n); 11 | 12 | for (std::size_t i = 0; i < n; i++) { 13 | outdegrees[i] = adj[i].size(); 14 | } 15 | return outdegrees; 16 | } 17 | 18 | [[nodiscard]] std::vector getIndegrees() const { 19 | std::vector indegrees(n); 20 | 21 | for (const auto& adjList : adj) { 22 | for (auto neighbor : adjList) { 23 | indegrees[neighbor]++; 24 | } 25 | } 26 | 27 | return indegrees; 28 | } 29 | 30 | }; 31 | 32 | 33 | int main() { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /5/5.2-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::mt19937 gen(std::random_device{}()); 10 | 11 | namespace sr = std::ranges; 12 | 13 | int main() { 14 | constexpr size_t N = 1000; 15 | constexpr size_t trials = 1000; 16 | 17 | std::vector hats(N); 18 | std::iota(hats.begin(), hats.end(), 1); 19 | size_t count = 0; 20 | for (size_t i = 0; i < trials; i++) { 21 | auto shuffled_hats = hats; 22 | sr::shuffle(shuffled_hats, gen); 23 | for (size_t j = 0; j < N; j++) { 24 | if (shuffled_hats[j] == hats[j]) { 25 | count++; 26 | } 27 | } 28 | } 29 | std::cout << "Average matched count : " << static_cast(count) / static_cast(trials) << '\n'; 30 | 31 | } -------------------------------------------------------------------------------- /5/5.3-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::mt19937 gen(std::random_device{}()); 8 | 9 | std::unordered_set randomSample(size_t m, size_t n) { 10 | assert(m <= n); 11 | if (m == 0) { 12 | std::unordered_set res; 13 | return res; 14 | } else { 15 | std::unordered_set res = randomSample(m - 1, n - 1); 16 | std::uniform_int_distribution<> dist(1, n); 17 | auto i = dist(gen); 18 | if (res.contains(i)) { 19 | res.insert(n); 20 | } else { 21 | res.insert(i); 22 | } 23 | return res; 24 | } 25 | } 26 | 27 | int main() { 28 | constexpr size_t N = 20; 29 | auto v = randomSample(8, N); 30 | for (auto n : v) { 31 | std::cout << n << ' '; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /7/7.2-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | size_t partition(std::vector& A, size_t p, size_t r) { 8 | T x = A[r]; 9 | size_t i = p; 10 | size_t equal_count = 0; 11 | for (size_t j = p; j < r; j++) { 12 | if (A[j] >= x) { 13 | std::swap(A[i], A[j]); 14 | i++; 15 | } 16 | } 17 | std::swap(A[i], A[r]); 18 | return i; 19 | } 20 | 21 | template 22 | void quickSort(std::vector& A, size_t p, size_t r) { 23 | if (p < r && r < A.size()) { 24 | size_t q = partition(A, p, r); 25 | quickSort(A, p, q - 1); 26 | quickSort(A, q + 1, r); 27 | } 28 | } 29 | 30 | int main() { 31 | constexpr size_t SIZE = 50'000; 32 | std::vector v (SIZE); 33 | quickSort(v, 0, v.size() - 1); // very slow 34 | } -------------------------------------------------------------------------------- /16/16.2-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | double fractionalKnapsack(std::vector>& items, double W) { 10 | assert(W > 0.0); 11 | assert(sr::all_of(items, [](auto& p) {return p.first > 0.0 && p.second > 0.0;})); 12 | sr::sort(items, [](auto& p1, auto& p2) {return p1.first / p1.second > p2.first / p2.second;}); 13 | double currWeight = 0.0; 14 | double finalValue = 0.0; 15 | for (const auto& [value, weight] : items) { 16 | if (currWeight + weight <= W) { 17 | currWeight += weight; 18 | finalValue += value; 19 | } else { 20 | auto remain = W - weight; 21 | finalValue += remain * value / weight; 22 | } 23 | } 24 | return finalValue; 25 | } 26 | 27 | int main() { 28 | } 29 | -------------------------------------------------------------------------------- /7/7.1_description_of_quicksort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace sr = std::ranges; 7 | 8 | template 9 | size_t partition(std::vector& A, size_t p, size_t r) { 10 | T x = A[r]; 11 | size_t i = p; 12 | for (size_t j = p; j < r; j++) { 13 | if (A[j] <= x) { 14 | std::swap(A[i], A[j]); 15 | i++; 16 | } 17 | } 18 | std::swap(A[i], A[r]); 19 | return i; 20 | } 21 | 22 | template 23 | void quickSort(std::vector& A, size_t p, size_t r) { 24 | if (p < r && r < A.size()) { 25 | size_t q = partition(A, p, r); 26 | quickSort(A, p, q - 1); 27 | quickSort(A, q + 1, r); 28 | } 29 | } 30 | 31 | int main() { 32 | std::vector v {3, 2, 6, 1, 5, 4}; 33 | quickSort(v, 0, v.size() - 1); 34 | assert(sr::is_sorted(v)); 35 | } -------------------------------------------------------------------------------- /34/34.5-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | bool SubsetSumUnary(const std::vector& S, std::size_t t) { 10 | if (S.empty()) { 11 | return false; 12 | } 13 | const std::size_t n = S.size(); 14 | assert(sr::find(S, 0) == S.end()); 15 | std::vector> A(n, std::vector(t + 1)); 16 | A[0][0] = true; 17 | A[0][S[0]] = true; 18 | for (std::size_t i = 1; i < n; i++) { 19 | for (std::size_t j = 1; j <= t; j++) { 20 | A[i][j] = A[i - 1][j] || (j >= S[i] && A[i - 1][j - S[i]]); 21 | } 22 | } 23 | return A[n - 1][t]; 24 | } 25 | 26 | int main() { 27 | assert(SubsetSumUnary(std::vector{2, 3, 4, 5}, 8)); 28 | assert(!SubsetSumUnary(std::vector{2, 3, 4, 5}, 16)); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /15/15-9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | size_t BreakString(size_t n, std::vector& B) { 8 | size_t m = B.size(); 9 | std::vector B_ (m + 2); 10 | B_[m + 1] = n; 11 | for (size_t i = 1; i <= m; i++) { 12 | B_[i] = B[i - 1]; 13 | } 14 | B = B_; 15 | std::vector> C (m + 1, std::vector (m + 2)); 16 | for (size_t i = m - 1; i < m; i--) { 17 | for (size_t j = i + 2; j <= m + 1; j++) { 18 | C[i][j] = std::numeric_limits::max(); 19 | for (size_t k = i + 1; k <= j - 1; k++) { 20 | C[i][j] = std::min({C[i][j], C[i][k] + C[k][j] + B[j] - B[i]}); 21 | } 22 | } 23 | } 24 | return C[0][m + 1]; 25 | } 26 | 27 | int main() { 28 | std::vector B {2, 8, 10}; 29 | std::cout << BreakString(20, B); 30 | 31 | } -------------------------------------------------------------------------------- /32/32.1_the_naive_string_matching_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::vector NaiveStringMatcher(const std::string& T, const std::string& P) { 9 | assert(!T.empty() && !P.empty()); 10 | const std::size_t n = T.length(); 11 | const std::size_t m = P.length(); 12 | std::vector res; 13 | if (n < m) { 14 | return res; 15 | } 16 | std::string_view T_sv (T); 17 | std::string_view P_sv (P); 18 | for (std::size_t s = 0; s <= n - m; s++) { 19 | if (P_sv.substr(0, m) == T_sv.substr(s, m)) { 20 | res.push_back(s); 21 | } 22 | } 23 | return res; 24 | } 25 | 26 | int main() { 27 | auto res = NaiveStringMatcher("acaabc", "aab"); 28 | for (auto shift : res) { 29 | std::cout << shift << ' '; 30 | } 31 | std::cout << '\n'; 32 | } -------------------------------------------------------------------------------- /10/10.3-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct GC { 9 | std::array prev; 10 | std::array next; 11 | std::array key = {0}; 12 | 13 | size_t free = 0; 14 | size_t head = 0; 15 | 16 | GC() { 17 | for (size_t i = 0; i < N; i++) { 18 | prev[i] = i - 1; 19 | next[i] = i + 1; 20 | } 21 | next[N - 1] = -1; 22 | } 23 | 24 | size_t AllocateObject() { 25 | if (free == -1) { 26 | throw std::runtime_error("out of space"); 27 | } else { 28 | size_t x = free; 29 | free = next[x]; 30 | return x; 31 | } 32 | } 33 | 34 | void FreeObject(size_t x) { 35 | next[x] = free; 36 | free = x; 37 | } 38 | }; 39 | 40 | 41 | int main() { 42 | 43 | } -------------------------------------------------------------------------------- /10/10.1-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct TwoStack { 9 | std::vector data; 10 | size_t top1; 11 | size_t top2; 12 | TwoStack(size_t n) : data(n), top1 {0}, top2 {n - 1} {assert(n);} 13 | 14 | void Push1(const T& x) { 15 | data[top1++] = x; 16 | } 17 | 18 | void Push2(const T& x) { 19 | data[top2--] = x; 20 | } 21 | 22 | T Pop1(const T& x) { 23 | if (top1 == 0) { 24 | throw std::underflow_error("Stack underflow"); 25 | } else { 26 | return data[--top1]; 27 | } 28 | } 29 | 30 | T Pop2(const T& x) { 31 | if (top2 == data.size() - 1) { 32 | throw std::underflow_error("Stack underflow"); 33 | } else { 34 | return data[++top2]; 35 | } 36 | } 37 | }; 38 | 39 | 40 | int main() { 41 | 42 | } -------------------------------------------------------------------------------- /7/7.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | template 10 | size_t partition(std::vector& A, size_t p, size_t r) { 11 | T x = A[r]; 12 | size_t i = p; 13 | size_t equal_count = 0; 14 | for (size_t j = p; j < r; j++) { 15 | if (A[j] >= x) { 16 | std::swap(A[i], A[j]); 17 | i++; 18 | } 19 | } 20 | std::swap(A[i], A[r]); 21 | return i; 22 | } 23 | 24 | template 25 | void quickSort(std::vector& A, size_t p, size_t r) { 26 | if (p < r && r < A.size()) { 27 | size_t q = partition(A, p, r); 28 | quickSort(A, p, q - 1); 29 | quickSort(A, q + 1, r); 30 | } 31 | } 32 | 33 | int main() { 34 | std::vector v {3, 2, 6, 1, 5, 4}; 35 | quickSort(v, 0, v.size() - 1); 36 | assert(sr::is_sorted(v, std::greater<>())); 37 | } -------------------------------------------------------------------------------- /10/10.3_implementing_pointers_and_objects.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct GC { 9 | std::array prev; 10 | std::array next; 11 | std::array key = {0}; 12 | 13 | size_t free = 0; 14 | size_t head = 0; 15 | 16 | GC() { 17 | for (size_t i = 0; i < N; i++) { 18 | prev[i] = i - 1; 19 | next[i] = i + 1; 20 | } 21 | next[N - 1] = -1; 22 | } 23 | 24 | size_t AllocateObject() { 25 | if (free == -1) { 26 | throw std::runtime_error("out of space"); 27 | } else { 28 | size_t x = free; 29 | free = next[x]; 30 | return x; 31 | } 32 | } 33 | 34 | void FreeObject(size_t x) { 35 | next[x] = free; 36 | free = x; 37 | } 38 | }; 39 | 40 | 41 | int main() { 42 | 43 | } -------------------------------------------------------------------------------- /5/5.3-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | 11 | int main() { 12 | constexpr size_t N = 20; 13 | constexpr size_t trials = 1000; 14 | std::mt19937 gen(std::random_device{}()); 15 | std::uniform_int_distribution<> dist(1, std::pow(N, 3)); 16 | size_t unique_count = 0; 17 | for (size_t t = 0; t < trials; t++) { 18 | std::vector v(N); 19 | for (size_t i = 0; i < N - 1; i++) { 20 | v[i] = dist(gen); 21 | } 22 | sr::sort(v); 23 | v.erase(sr::unique(v), v.end()); 24 | if (v.size() == N) { 25 | unique_count++; 26 | } 27 | } 28 | std::cout << "Probability that elems are unique : " << static_cast(unique_count) / static_cast(trials) << '\n'; 29 | std::cout << "1 - (1 / N) : " << 1.0 - 1.0 / N << '\n'; 30 | 31 | } -------------------------------------------------------------------------------- /5/5.4.2_balls_and_bins.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::mt19937 gen(std::random_device{}()); 11 | 12 | namespace sr = std::ranges; 13 | 14 | int main() { 15 | constexpr size_t N = 100; 16 | constexpr size_t trials = 1000; 17 | std::uniform_int_distribution<> toss(0, N - 1); 18 | size_t toss_count = 0; 19 | for (size_t t = 0; t < trials; t++) { 20 | std::vector bin(N); 21 | while (true) { 22 | bin[toss(gen)] = 1; 23 | toss_count++; 24 | if (sr::all_of(bin, [](int i){return i;})) { 25 | break; 26 | } 27 | } 28 | } 29 | 30 | std::cout << "Expected number of tosses : " << static_cast(toss_count) / 31 | static_cast(trials) << '\n'; 32 | std::cout << "N ln N : " << N * std::log(N); 33 | 34 | } -------------------------------------------------------------------------------- /8/8-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sr = std::ranges; 9 | 10 | void inplaceCountingSort(std::vector& A, size_t k) { 11 | assert(*sr::max_element(A) <= k); 12 | std::vector C (k + 1); 13 | for (auto n : A) { 14 | C[n]++; 15 | } 16 | for (size_t j = 1; j <= k; j++) { 17 | C[j] += C[j - 1]; 18 | } 19 | size_t prev_count = 0; 20 | for (size_t i = 0; i <= k; ) { 21 | size_t count = C[i]; 22 | for (size_t j = prev_count; j <= count; j++) { 23 | A[j] = i; 24 | } 25 | while (C[i] == count) { 26 | i++; 27 | } 28 | prev_count = count; 29 | } 30 | } 31 | 32 | int main() { 33 | std::vector v {2, 5, 3, 0, 2, 3, 0, 3}; 34 | inplaceCountingSort(v, 7); 35 | for (auto n : v) { 36 | std::cout << n << ' '; 37 | } 38 | } -------------------------------------------------------------------------------- /9/9.3-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | 11 | template 12 | std::vector kClosestToMedian(std::vector& A, size_t k) { 13 | assert(k <= A.size()); 14 | sr::nth_element(A, A.begin() + A.size() / 2); 15 | T median = A[A.size() / 2]; 16 | auto B = A; 17 | sr::transform(B, B.begin(), [median](auto n) {return std::abs(n - median);}); 18 | sr::nth_element(B, B.begin() + k); 19 | auto diff_threshold = B[k]; 20 | std::vector result; 21 | for (auto n : A) { 22 | if (std::abs(n - median) < diff_threshold) { 23 | result.push_back(n); 24 | } 25 | } 26 | return result; 27 | } 28 | 29 | int main() { 30 | std::vector v {3, 2, 6, 1, 5, 4, 8, 7}; 31 | auto w = kClosestToMedian(v, 3); 32 | for (auto n : w) { 33 | std::cout << n << ' '; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /10/10.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct Queue { 9 | std::vector data; 10 | size_t head = 0; 11 | size_t tail = 0; 12 | }; 13 | 14 | template 15 | void Enqueue(Queue& q, const T& x) { 16 | if (q.head == q.tail + 1 || (q.head == 0 && q.tail == q.data.size() - 1)) { 17 | throw std::overflow_error("Queue overflow"); 18 | } 19 | q.data[q.tail] = x; 20 | if (q.tail == q.data.size() - 1) { 21 | q.tail = 0; 22 | } else { 23 | q.tail++; 24 | } 25 | } 26 | 27 | template 28 | void Dequeue(Queue& q) { 29 | if (q.head == q.tail) { 30 | throw std::underflow_error("Queue underflow"); 31 | } 32 | T x = q.data[q.head]; 33 | if (q.head == q.data.size() - 1) { 34 | q.head = 0; 35 | } else { 36 | q.head++; 37 | } 38 | return x; 39 | } 40 | 41 | int main() { 42 | 43 | } -------------------------------------------------------------------------------- /31/31.9_integer_factorization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::mt19937 gen(std::random_device{}()); 9 | 10 | std::unordered_set PollardRho(std::size_t n) { 11 | std::size_t i = 1; 12 | std::uniform_int_distribution<> dist(0, n - 1); 13 | auto x = dist(gen); 14 | std::size_t y = x; 15 | std::size_t k = 2; 16 | std::unordered_set res; 17 | while (i <= n) { 18 | i++; 19 | x = (x * x - 1) % n; 20 | auto d = std::gcd(y - x, n); 21 | if (d != 1 && d != n) { 22 | res.insert(d); 23 | } 24 | if (i == k) { 25 | y = x; 26 | k *= 2; 27 | } 28 | } 29 | return res; 30 | } 31 | 32 | int main() { 33 | auto factors = PollardRho(1328789); 34 | for (auto factor : factors) { 35 | std::cout << factor << ' '; 36 | } 37 | std::cout << '\n'; 38 | 39 | } -------------------------------------------------------------------------------- /7/7.2-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | template 10 | size_t partition(std::vector& A, size_t p, size_t r) { 11 | T x = A[r]; 12 | size_t i = p; 13 | size_t equal_count = 0; 14 | for (size_t j = p; j < r; j++) { 15 | if (A[j] >= x) { 16 | std::swap(A[i], A[j]); 17 | i++; 18 | } 19 | } 20 | std::swap(A[i], A[r]); 21 | return i; 22 | } 23 | 24 | template 25 | void quickSort(std::vector& A, size_t p, size_t r) { 26 | if (p < r && r < A.size()) { 27 | size_t q = partition(A, p, r); 28 | quickSort(A, p, q - 1); 29 | quickSort(A, q + 1, r); 30 | } 31 | } 32 | 33 | int main() { 34 | constexpr size_t SIZE = 50'000; 35 | std::vector v (SIZE); 36 | std::iota(v.begin(), v.end(), 0); 37 | sr::reverse(v); 38 | quickSort(v, 0, v.size() - 1); // very slow 39 | } -------------------------------------------------------------------------------- /27/27-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace se = std::execution; 13 | namespace sr = std::ranges; 14 | 15 | template 16 | void SumArrays(const std::vector& A, const std::vector& B, std::vector& C) { 17 | std::transform(se::unseq, A.begin(), A.end(), B.begin(), C.begin(), std::plus<>{}); 18 | } 19 | 20 | int main() { 21 | constexpr std::size_t N = 20; 22 | 23 | std::mt19937 gen(std::random_device{}()); 24 | std::vector A (N); 25 | std::iota(A.begin(), A.end(), 0); 26 | std::vector B (N); 27 | std::iota(B.begin(), B.end(), 0); 28 | sr::shuffle(A, gen); 29 | sr::shuffle(B, gen); 30 | std::vector C (N); 31 | SumArrays(A, B, C); 32 | for (auto n : C) { 33 | std::cout << n << ' '; 34 | } 35 | std::cout << '\n'; 36 | 37 | 38 | } -------------------------------------------------------------------------------- /7/7.1-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace sr = std::ranges; 7 | 8 | template 9 | size_t partition(std::vector& A, size_t p, size_t r) { 10 | T x = A[r]; 11 | size_t i = p; 12 | size_t equal_count = 0; 13 | for (size_t j = p; j < r; j++) { 14 | if (A[j] <= x) { 15 | if (A[j] == x) { 16 | equal_count++; 17 | } 18 | std::swap(A[i], A[j]); 19 | i++; 20 | } 21 | } 22 | std::swap(A[i], A[r]); 23 | return i - (equal_count) / 2; 24 | } 25 | 26 | template 27 | void quickSort(std::vector& A, size_t p, size_t r) { 28 | if (p < r && r < A.size()) { 29 | size_t q = partition(A, p, r); 30 | quickSort(A, p, q - 1); 31 | quickSort(A, q + 1, r); 32 | } 33 | } 34 | 35 | int main() { 36 | std::vector v {3, 2, 6, 1, 5, 4}; 37 | quickSort(v, 0, v.size() - 1); 38 | assert(sr::is_sorted(v)); 39 | } -------------------------------------------------------------------------------- /7/7-1_hoare_partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace sr = std::ranges; 7 | 8 | template 9 | size_t hoarePartition(std::vector& A, size_t p, size_t r) { 10 | T x = A[p]; 11 | size_t i = p - 1; 12 | size_t j = r + 1; 13 | while (true) { 14 | do { 15 | j--; 16 | } while (A[j] > x); 17 | do { 18 | i++; 19 | } while (A[i] < x); 20 | if (i < j) { 21 | std::swap(A[i], A[j]); 22 | } else { 23 | return j; 24 | } 25 | } 26 | } 27 | 28 | template 29 | void quickSort(std::vector& A, size_t p, size_t r) { 30 | if (p < r && r < A.size()) { 31 | size_t q = hoarePartition(A, p, r); 32 | quickSort(A, p, q - 1); 33 | quickSort(A, q + 1, r); 34 | } 35 | } 36 | 37 | int main() { 38 | std::vector v {3, 2, 6, 1, 5, 4}; 39 | quickSort(v, 0, v.size() - 1); 40 | assert(sr::is_sorted(v)); 41 | } -------------------------------------------------------------------------------- /22/22.4_topological_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class Graph { 10 | std::vector> adj; 11 | public: 12 | Graph() : adj(n) { 13 | } 14 | 15 | 16 | void DFSVisit(std::size_t u, std::vector& visited, std::list& topSort) { 17 | visited[u] = true; 18 | for (auto v : adj[u]) { 19 | if (!visited[v]) { 20 | DFSVisit(v, visited, topSort); 21 | } 22 | } 23 | topSort.push_front(u); 24 | } 25 | 26 | std::list TopologicalSort() { 27 | std::list topSort; 28 | std::vector visited (n); 29 | 30 | for (std::size_t u = 0; u < n; u++) { 31 | if (!visited[u]) { 32 | DFSVisit(u, visited, topSort); 33 | } 34 | } 35 | return topSort; 36 | } 37 | }; 38 | 39 | 40 | int main() { 41 | 42 | } 43 | -------------------------------------------------------------------------------- /7/7-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | template 10 | std::pair partition(std::vector& A, size_t p, size_t r) { 11 | T x = A[r]; 12 | size_t l = p, m = p, h = r; 13 | while (m <= h) { 14 | if (A[m] < x) { 15 | std::swap(A[l], A[m]); 16 | l++; 17 | m++; 18 | } else if (A[m] > x) { 19 | std::swap(A[m], A[h]); 20 | h--; 21 | } else { 22 | m++; 23 | } 24 | } 25 | return {l, m - 1}; 26 | } 27 | 28 | template 29 | void quickSort(std::vector& A, size_t p, size_t r) { 30 | if (p < r && r < A.size()) { 31 | auto [l, m] = partition(A, p, r); 32 | quickSort(A, p, l - 1); 33 | quickSort(A, m + 1, r); 34 | } 35 | } 36 | 37 | int main() { 38 | std::vector v {3, 2, 6, 1, 5, 4}; 39 | quickSort(v, 0, v.size() - 1); 40 | assert(sr::is_sorted(v)); 41 | } -------------------------------------------------------------------------------- /9/9.3-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sr = std::ranges; 9 | namespace srv = std::ranges::views; 10 | 11 | template 12 | size_t partition(std::vector& A, size_t p, size_t r) { 13 | sr::nth_element(A | srv::drop(p) | srv::take(r), A.begin() + (p + r) / 2); 14 | T x = A[(p + r) / 2]; 15 | size_t i = p; 16 | for (size_t j = p; j < r; j++) { 17 | if (A[j] <= x) { 18 | std::swap(A[i], A[j]); 19 | i++; 20 | } 21 | } 22 | std::swap(A[i], A[r]); 23 | return i; 24 | } 25 | 26 | template 27 | void quickSort(std::vector& A, size_t p, size_t r) { 28 | if (p < r && r < A.size()) { 29 | size_t q = partition(A, p, r); 30 | quickSort(A, p, q - 1); 31 | quickSort(A, q + 1, r); 32 | } 33 | } 34 | 35 | int main() { 36 | std::vector v {4, 2, 1, 5, 3, 6}; 37 | quickSort(v, 0, v.size() - 1); 38 | assert(sr::is_sorted(v)); 39 | 40 | } -------------------------------------------------------------------------------- /22/22.1-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | class Graph { 7 | std::vector> adj; 8 | public: 9 | Graph() : adj(n) {} 10 | 11 | [[nodiscard]] Graph transpose() const { 12 | Graph transposed; 13 | 14 | for (std::size_t i = 0; i < n; i++) { 15 | for (auto neighbor : adj[i]) { 16 | transposed.adj[neighbor].push_back(i); 17 | } 18 | } 19 | return transposed; 20 | } 21 | }; 22 | 23 | template 24 | class GraphM { 25 | std::array adj; 26 | public: 27 | [[nodiscard]] GraphM transpose() const { 28 | GraphM transposed; 29 | transposed.adj = adj; 30 | for (std::size_t i = 0; i < n; i++) { 31 | for (std::size_t j = 0; j < i; j++) { 32 | std::swap(transposed.adj[i * n + j], transposed.adj[j * n + i]); 33 | } 34 | } 35 | return transposed; 36 | } 37 | }; 38 | 39 | 40 | int main() { 41 | 42 | } 43 | -------------------------------------------------------------------------------- /5/5.2_hiring_problem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | 11 | std::mt19937 gen(std::random_device{}()); 12 | 13 | size_t hiringCost(const std::vector& v) { 14 | int best = 0; 15 | size_t count = 0; 16 | for (auto n : v) { 17 | if (n > best) { 18 | best = n; 19 | count++; 20 | } 21 | } 22 | return count; 23 | } 24 | 25 | int main() { 26 | constexpr size_t N = 1000; 27 | constexpr size_t trials = 1000; 28 | size_t cost = 0; 29 | 30 | for (size_t i = 0; i < trials; i++) { 31 | std::vector candidates(N); 32 | std::iota(candidates.begin(), candidates.end(), 1); 33 | sr::shuffle(candidates, gen); 34 | cost += hiringCost(candidates); 35 | } 36 | 37 | std::cout << "Average hiring cost : " << static_cast(cost) / static_cast(trials) << '\n'; 38 | std::cout << "ln n : " << std::log(N) << '\n'; 39 | } -------------------------------------------------------------------------------- /17/17-1_a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace sr = std::ranges; 13 | 14 | template 15 | void bitReversalPermutation(std::vector& v) { 16 | assert(v.size() > 128 && v.size() <= 256); 17 | std::vector checked (v.size()); 18 | for (std::size_t i = 0; i < v.size(); i++) { 19 | if (!checked[i]) { 20 | std::bitset<8> bits (i); 21 | std::string str = bits.to_string(); 22 | sr::reverse(str); 23 | std::bitset<8> rev_bits (str); 24 | std::size_t j = rev_bits.to_ulong(); 25 | std::swap(v[i], v[j]); 26 | checked[i]++; 27 | checked[j]++; 28 | } 29 | } 30 | } 31 | 32 | int main() { 33 | std::vector v (256); 34 | std::iota(v.begin(), v.end(), 0); 35 | bitReversalPermutation(v); 36 | for (auto n : v) { 37 | std::cout << n << ' '; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /21/21.3_disjoint_set_forests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class Node { 5 | T element; 6 | Node* parent = this; 7 | std::size_t rank = 0; 8 | 9 | public: 10 | Node(const T& element) : element(element) {} 11 | }; 12 | 13 | template 14 | Node MakeSet(const T& element) { 15 | Node node(element); 16 | return node; 17 | } 18 | 19 | template 20 | void Link(Node* x, Node* y) { 21 | if (!x || !y) { 22 | return; 23 | } 24 | if (x->rank > y->rank) { 25 | y->parent = x; 26 | } else { 27 | x->parent = y; 28 | if (x->rank == y->rank) { 29 | y->rank++; 30 | } 31 | } 32 | } 33 | 34 | template 35 | void Union(Node* x, Node* y) { 36 | Link(FindSet(x), FindSet(y)); 37 | } 38 | 39 | template 40 | Node* FindSet(Node* x) { 41 | if (!x) { 42 | return nullptr; 43 | } 44 | if (x != x->parent) { 45 | x->parent = FindSet(x->parent); 46 | } 47 | return x->parent; 48 | } 49 | 50 | int main() { 51 | 52 | } -------------------------------------------------------------------------------- /7/7-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | template 10 | size_t partition(std::vector& A, size_t p, size_t r) { 11 | T x = A[r]; 12 | size_t i = p; 13 | for (size_t j = p; j < r; j++) { 14 | if (A[j] <= x) { 15 | std::swap(A[i], A[j]); 16 | i++; 17 | } 18 | } 19 | std::swap(A[i], A[r]); 20 | return i; 21 | } 22 | 23 | template 24 | void tailRecursiveQuickSort(std::vector& A, size_t p, size_t r) { 25 | while (p < r && r < A.size()) { 26 | size_t q = partition(A, p, r); 27 | size_t m = (p + r) / 2; 28 | if (q < m) { 29 | tailRecursiveQuickSort(A, p, q - 1); 30 | p = q + 1; 31 | } else { 32 | tailRecursiveQuickSort(A, q + 1, r); 33 | r = q - 1; 34 | } 35 | } 36 | } 37 | 38 | int main() { 39 | std::vector v {3, 2, 6, 1, 5, 4}; 40 | tailRecursiveQuickSort(v, 0, v.size() - 1); 41 | assert(sr::is_sorted(v)); 42 | } -------------------------------------------------------------------------------- /6/6.3_building_a_heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | size_t parent(size_t i) { 10 | return i / 2; 11 | } 12 | 13 | size_t left(size_t i) { 14 | return 2 * i + 1; 15 | } 16 | 17 | size_t right(size_t i) { 18 | return 2 * i + 2; 19 | } 20 | 21 | template 22 | void maxHeapify(std::vector& A, size_t i) { 23 | auto l = left(i); 24 | auto r = right(i); 25 | size_t largest = i; 26 | if (l < A.size() && A[l] > A[i]) { 27 | largest = l; 28 | } 29 | if (r < A.size() && A[r] > A[largest]) { 30 | largest = r; 31 | } 32 | if (largest != i) { 33 | std::swap(A[i], A[largest]); 34 | maxHeapify(A, largest); 35 | } 36 | } 37 | 38 | template 39 | void buildMaxHeap(std::vector& A) { 40 | for (size_t i = A.size() / 2; i < A.size(); i--) { 41 | maxHeapify(A, i); 42 | } 43 | } 44 | 45 | int main() { 46 | std::vector v {3, 1, 4, 1, 5, 9}; 47 | buildMaxHeap(v); 48 | assert(sr::is_heap(v)); 49 | } -------------------------------------------------------------------------------- /5/5.4.3_streaks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::mt19937 gen(std::random_device{}()); 9 | 10 | int main() { 11 | constexpr size_t N = 100; 12 | constexpr size_t trials = 1000; 13 | std::bernoulli_distribution coin(0.5); 14 | size_t longest_streak_count = 0; 15 | for (size_t t = 0; t < trials; t++) { 16 | size_t longest_streak = 0; 17 | size_t current_streak = 0; 18 | for (size_t i = 0; i < N; i++) { 19 | if (coin(gen)) { 20 | current_streak++; 21 | } else { 22 | longest_streak = std::max(longest_streak, current_streak); 23 | current_streak = 0; 24 | } 25 | } 26 | longest_streak = std::max(longest_streak, current_streak); 27 | longest_streak_count += longest_streak; 28 | } 29 | 30 | std::cout << "Expected number of longest streak : " << static_cast(longest_streak_count) / 31 | static_cast(trials) << '\n'; 32 | std::cout << "ln N : " << std::log(N); 33 | 34 | } -------------------------------------------------------------------------------- /5/5.4-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::mt19937 gen(std::random_device{}()); 11 | std::uniform_int_distribution<> birthday(1, 365); 12 | 13 | int main() { 14 | constexpr size_t N = 94; 15 | constexpr size_t trials = 1000; 16 | size_t same_birthday_count = 0; 17 | for (size_t t = 0; t < trials; t++) { 18 | std::vector people(N); 19 | std::unordered_map freq; 20 | for (size_t i = 0; i < N; i++) { 21 | people[i] = birthday(gen); 22 | freq[people[i]]++; 23 | } 24 | int max_freq = 0; 25 | for (const auto& [day, ppl] : freq) { 26 | max_freq = std::max(max_freq, ppl); 27 | } 28 | if (max_freq >= 3) { 29 | same_birthday_count++; 30 | } 31 | } 32 | 33 | std::cout << "Probability that at least 3 people have the same birthday with " << N << 34 | " peoples : " << static_cast(same_birthday_count) / static_cast(trials) << '\n'; 35 | 36 | 37 | } -------------------------------------------------------------------------------- /2/2_3-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | bool binarySearchRecursive(const std::vector& A, size_t p, size_t q, const T& key) { 8 | if (p > q || q > A.size()) { 9 | return false; 10 | } 11 | size_t m = p + (q - p) / 2; 12 | if (A[m] > key) { 13 | return binarySearchRecursive(A, p, m - 1, key); 14 | } else if (A[m] < key) { 15 | return binarySearchRecursive(A, m + 1, q, key); 16 | } else { 17 | return true; 18 | } 19 | } 20 | 21 | template 22 | bool binarySearch(const std::vector& A, const T& key) { 23 | if (A.empty()) return false; 24 | return binarySearchRecursive(A, 0, A.size() - 1, key); 25 | } 26 | 27 | int main() { 28 | std::vector v {1, 2, 4, 6, 7}; 29 | assert(!binarySearch(v, 0)); 30 | assert(binarySearch(v, 1)); 31 | assert(binarySearch(v, 2)); 32 | assert(!binarySearch(v, 3)); 33 | assert(binarySearch(v, 4)); 34 | assert(!binarySearch(v, 5)); 35 | assert(binarySearch(v, 6)); 36 | assert(binarySearch(v, 7)); 37 | assert(!binarySearch(v, 8)); 38 | } -------------------------------------------------------------------------------- /5/5.4.1_the_birthday_paradox.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sr = std::ranges; 11 | 12 | std::mt19937 gen(std::random_device{}()); 13 | std::uniform_int_distribution<> birthday(1, 365); 14 | 15 | int main() { 16 | constexpr size_t N = 23; 17 | constexpr size_t trials = 1000; 18 | size_t same_birthday_count = 0; 19 | for (size_t t = 0; t < trials; t++) { 20 | std::vector people(N); 21 | for (size_t i = 0; i < N; i++) { 22 | people[i] = birthday(gen); 23 | } 24 | sr::sort(people); 25 | people.erase(sr::unique(people), people.end()); 26 | if (people.size() < N) { 27 | same_birthday_count++; 28 | } 29 | } 30 | 31 | std::cout << "Probability that at least 2 people have the same birthday : " << static_cast(same_birthday_count) / 32 | static_cast(trials) << '\n'; 33 | std::cout << "1 - exp(-k(k-1)/2n) : " << 1.0 - std::exp(-static_cast(N) * (N - 1) / (2.0 * 365)); 34 | 35 | 36 | } -------------------------------------------------------------------------------- /2/2_3_merge_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | void merge(std::vector& A, size_t p, size_t q, size_t r) { 8 | size_t i = p; 9 | size_t j = q; 10 | std::vector B (r - p); 11 | for (size_t k = 0; k < B.size(); k++) { 12 | if (A[i] < A[j] || j >= r) { 13 | B[k] = A[i]; 14 | i++; 15 | } else { 16 | B[k] = A[j]; 17 | j++; 18 | } 19 | } 20 | std::copy(A.begin() + p, A.begin() + r, B.begin()); 21 | } 22 | 23 | template 24 | void mergeSortHelper(std::vector& A, size_t p, size_t r) { 25 | if (p < r) { 26 | size_t q = p + (r - p) / 2; 27 | mergeSortHelper(A, p, q); 28 | mergeSortHelper(A, q + 1, r); 29 | merge(A, p, q, r); 30 | } 31 | } 32 | 33 | template 34 | void mergeSort(std::vector& A) { 35 | mergeSortHelper(A, 0, A.size() - 1); 36 | } 37 | 38 | int main() { 39 | std::vector v {5, 4, 3, 2, 1}; 40 | mergeSort(v); 41 | for (auto n : v) { 42 | std::cout << n << ' '; 43 | } 44 | 45 | 46 | } -------------------------------------------------------------------------------- /16/16-2_b.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sr = std::ranges; 11 | 12 | std::vector minimizeAverageCompletion(std::vector>& tasks) { 13 | sr::sort(tasks); // sort by release time - processing time - index 14 | auto [start_time, firstTime, firstIndex] = tasks.front(); 15 | int end_time = std::get<0>(tasks.back()); 16 | 17 | std::vector taskOrder; 18 | std::priority_queue, std::vector>, std::greater<>> remainingTimes; 19 | remainingTimes.emplace(firstTime, firstIndex); 20 | for (int time = start_time; time <= end_time; time++) { 21 | auto [currProcess, currIndex] = remainingTimes.top(); 22 | // process a task 23 | currProcess--; 24 | taskOrder.push_back(currIndex); 25 | remainingTimes.pop(); 26 | if (currProcess) { 27 | remainingTimes.emplace(currProcess, currIndex); 28 | } 29 | } 30 | return taskOrder; 31 | } 32 | 33 | int main() { 34 | } 35 | -------------------------------------------------------------------------------- /8/8-5-d.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sr = std::ranges; 11 | 12 | std::mt19937 gen(std::random_device{}()); 13 | 14 | void averageSort(std::vector& v, size_t k) { 15 | std::vector> V (k); 16 | for (size_t i = 0; i < v.size(); i++) { 17 | V[i % k].push_back(v[i]); 18 | } 19 | for (auto& V_ : V) { 20 | sr::sort(V_); 21 | } 22 | for (size_t m = 0; m < k; m++) { 23 | for (size_t i = 0; i < V[m].size(); i++) { 24 | v[m + i * k] = V[m][i]; 25 | } 26 | } 27 | for (size_t i = 0; i < v.size() - k; i++) { 28 | assert(v[i] <= v[i + k]); 29 | } 30 | } 31 | 32 | int main() { 33 | constexpr size_t N = 500; 34 | 35 | std::vector v (N); 36 | std::iota(v.begin(), v.end(), 0); 37 | sr::shuffle(v, gen); 38 | size_t k = 10; 39 | averageSort(v, k); 40 | 41 | for (size_t i = 0; i < N; i++) { 42 | std::cout << v[i] << ' '; 43 | if (i % k == (k - 1)) std::cout << '\n'; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /31/31-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::size_t BinaryGCD(std::size_t a, std::size_t b) { 7 | if (a < b) { 8 | return BinaryGCD(b, a); 9 | } 10 | if (a & 1) { 11 | if (b & 1) { 12 | if (b == 1) { 13 | return 1; 14 | } else { 15 | return BinaryGCD((a - b) >> 1, b); 16 | } 17 | } else { 18 | if (b == 0) { 19 | return a; 20 | } else { 21 | return BinaryGCD(a, b >> 1); 22 | } 23 | } 24 | } else { 25 | if (b & 1) { 26 | if (b == 1) { 27 | return 1; 28 | } else { 29 | return BinaryGCD(a >> 1, b); 30 | } 31 | } else { 32 | if (b == 0) { 33 | return a; 34 | } else { 35 | return BinaryGCD(a >> 1, b >> 1) << 1; 36 | } 37 | } 38 | } 39 | } 40 | 41 | int main() { 42 | std::size_t a = 4; 43 | std::size_t b = 36; 44 | std::cout << std::gcd(a, b) << '\n'; 45 | std::cout << BinaryGCD(a, b) << '\n'; 46 | 47 | 48 | } -------------------------------------------------------------------------------- /31/31.6-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::size_t ModularExponentiation(std::size_t a, std::size_t b, std::size_t n) { 9 | assert(n); 10 | std::size_t c = 0; 11 | std::size_t d = 1; 12 | auto k = std::bit_width(b); 13 | std::bitset<64> B(b); 14 | for (std::size_t i = k - 1; i < k; i--) { 15 | c *= 2; 16 | d = (d * d) % n; 17 | if (B[i]) { 18 | c++; 19 | d = (d * a) % n; 20 | } 21 | } 22 | return d; 23 | } 24 | 25 | std::size_t ModularExponentiation2(std::size_t a, std::size_t b, std::size_t n) { 26 | assert(n); 27 | std::size_t c = 0; 28 | std::size_t d = 1; 29 | std::size_t s = a; 30 | auto k = std::bit_width(b); 31 | std::bitset<64> B(b); 32 | for (std::size_t i = 0; i < k; i++) { 33 | if (B[i]) { 34 | d = (s * d) % n; 35 | c = (1u << i) + c; 36 | } 37 | s = (s * s) % n; 38 | } 39 | return d; 40 | } 41 | 42 | int main() { 43 | std::cout << ModularExponentiation(7, 560, 561) << '\n'; 44 | std::cout << ModularExponentiation2(7, 560, 561) << '\n'; 45 | 46 | } -------------------------------------------------------------------------------- /5/5-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::mt19937 gen(std::random_device{}()); 10 | 11 | int main() { 12 | constexpr size_t N = 100; 13 | constexpr size_t trials = 1000; 14 | std::uniform_int_distribution<> incr(1, N); 15 | 16 | size_t total_num = 0; 17 | for (size_t t = 0; t < trials; t++) { 18 | std::vector seq(N); 19 | size_t cur_num = 0; 20 | for (size_t i = 0; i < N; i++) { 21 | cur_num += incr(gen); 22 | seq[i] = cur_num; 23 | } 24 | cur_num = 0; 25 | size_t cur_index = 0; 26 | for (size_t i = 0; i < N; i++) { 27 | std::bernoulli_distribution cur_incr(1.0 / static_cast(seq[cur_index + 1] - seq[cur_index])); 28 | if (cur_incr(gen)) { 29 | cur_num += seq[cur_index + 1] - seq[cur_index]; 30 | cur_index++; 31 | } 32 | } 33 | total_num += cur_num; 34 | } 35 | std::cout << "Expected value of counter after N increment operations : " << static_cast(total_num) / static_cast(trials); 36 | 37 | 38 | } -------------------------------------------------------------------------------- /16/16.1-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | std::pair>, std::vector>> 10 | DynamicActivitySelect(std::vector>& intervals) { 11 | sr::sort(intervals, [](auto& a, auto& b) {return a.second < b.second;}); 12 | size_t n = intervals.size(); 13 | std::vector> c(n + 2, std::vector(n + 2)); 14 | std::vector> a(n + 2, std::vector(n + 2)); 15 | for (size_t l = 2; l <= n + 1; l++) { 16 | for (size_t i = 0; i <= n - l + 1; i++) { 17 | size_t j = i + l; 18 | size_t k = j - 1; 19 | while (intervals[i].second < intervals[k].second) { 20 | if (intervals[i].second <= intervals[k].first && intervals[k].second <= intervals[j].first 21 | && c[i][k] + c[k][j] + 1 > c[i][j]) { 22 | c[i][j] = c[i][k] + c[k][j] + 1; 23 | a[i][j] = k; 24 | } 25 | k--; 26 | } 27 | } 28 | } 29 | return {c, a}; 30 | } 31 | 32 | 33 | int main() { 34 | } 35 | -------------------------------------------------------------------------------- /22/22.4-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | enum class Color { 10 | White, 11 | Gray, 12 | Black 13 | }; 14 | 15 | using info_t = std::tuple; 16 | 17 | template 18 | class Graph { 19 | std::vector> adj; 20 | public: 21 | Graph() : adj(n) { 22 | } 23 | 24 | std::vector infos; 25 | 26 | std::size_t CountSimplePaths(std::size_t u, std::size_t v) { 27 | std::vector numPaths(n, -1); 28 | return CountSimplePaths(u, v, numPaths); 29 | } 30 | 31 | std::size_t CountSimplePaths(std::size_t u, std::size_t v, std::vector& numPaths) { 32 | if (u == v) { 33 | return 1; 34 | } else if (numPaths[u] != -1) { 35 | return numPaths[u]; 36 | } else { 37 | numPaths[u] = 0; 38 | for (auto w : adj[u]) { 39 | numPaths[u] += CountSimplePaths(w, v, numPaths); 40 | } 41 | } 42 | return numPaths[u]; 43 | } 44 | }; 45 | 46 | 47 | int main() { 48 | 49 | } 50 | -------------------------------------------------------------------------------- /6/6.2-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | size_t parent(size_t i) { 7 | return i / 2; 8 | } 9 | 10 | size_t left(size_t i) { 11 | return 2 * i + 1; 12 | } 13 | 14 | size_t right(size_t i) { 15 | return 2 * i + 2; 16 | } 17 | 18 | template 19 | void maxHeapify(std::vector& A, size_t i) { 20 | auto l = left(i); 21 | auto r = right(i); 22 | size_t largest = i; 23 | if (l < A.size() && A[l] > A[i]) { 24 | largest = l; 25 | } 26 | if (r < A.size() && A[r] > A[largest]) { 27 | largest = r; 28 | } 29 | if (largest != i) { 30 | std::swap(A[i], A[largest]); 31 | maxHeapify(A, largest); 32 | } 33 | } 34 | 35 | template 36 | void minHeapify(std::vector& A, size_t i) { 37 | auto l = left(i); 38 | auto r = right(i); 39 | size_t smallest = i; 40 | if (l < A.size() && A[l] < A[i]) { 41 | smallest = l; 42 | } 43 | if (r < A.size() && A[r] < A[smallest]) { 44 | smallest = r; 45 | } 46 | if (smallest != i) { 47 | std::swap(A[i], A[smallest]); 48 | minHeapify(A, smallest); 49 | } 50 | } 51 | 52 | int main() { 53 | 54 | } -------------------------------------------------------------------------------- /6/6.2-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | namespace srv = std::ranges::views; 11 | 12 | size_t parent(size_t i) { 13 | return i / 2; 14 | } 15 | 16 | size_t left(size_t i) { 17 | return 2 * i + 1; 18 | } 19 | 20 | size_t right(size_t i) { 21 | return 2 * i + 2; 22 | } 23 | 24 | template 25 | void maxHeapifyIterative(std::vector& A) { 26 | size_t i = 0; 27 | while (i <= A.size() / 2) { 28 | auto l = left(i); 29 | auto r = right(i); 30 | size_t largest = i; 31 | if (l < A.size() && A[l] > A[i]) { 32 | largest = l; 33 | } 34 | if (r < A.size() && A[r] > A[largest]) { 35 | largest = r; 36 | } 37 | if (largest != i) { 38 | std::swap(A[i], A[largest]); 39 | i = largest; 40 | } else { 41 | return; 42 | } 43 | } 44 | } 45 | 46 | 47 | int main() { 48 | std::vector v {3, 1, 4, 1, 5, 9}; 49 | sr::make_heap(v | srv::drop(1)); 50 | maxHeapifyIterative(v); 51 | assert(sr::is_heap(v)); 52 | 53 | } -------------------------------------------------------------------------------- /16/16.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sr = std::ranges; 11 | 12 | std::map GreedyActivitySelector(std::vector>& intervals) { 13 | std::vector> endpoints; 14 | for (const auto& [start, finish] : intervals) { 15 | endpoints.emplace_back(start, start, true); 16 | endpoints.emplace_back(finish, start, false); 17 | } 18 | sr::sort(endpoints); 19 | size_t n = intervals.size(); 20 | std::set available; 21 | std::map used_map; 22 | for (size_t i = 0; i < n; i++) { 23 | available.insert(i); 24 | } 25 | for (const auto& [point, startOf, isStart] : endpoints) { 26 | if (isStart) { 27 | auto least_available = *available.begin(); 28 | available.erase(least_available); 29 | used_map[point] = least_available; 30 | } else { 31 | auto being_freed = used_map[startOf]; 32 | available.insert(being_freed); 33 | } 34 | } 35 | 36 | return used_map; 37 | } 38 | 39 | int main() { 40 | } 41 | -------------------------------------------------------------------------------- /9/9.3-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sr = std::ranges; 9 | namespace srv = std::ranges::views; 10 | 11 | template 12 | size_t partition(std::vector& A, size_t p, size_t r, const T& x) { 13 | size_t i = p; 14 | for (size_t j = p; j < r; j++) { 15 | if (A[j] <= x) { 16 | std::swap(A[i], A[j]); 17 | i++; 18 | } 19 | } 20 | std::swap(A[i], A[r]); 21 | return i; 22 | } 23 | 24 | template 25 | T Select(std::vector& A, size_t p, size_t r, size_t i) { 26 | if (p == r) { 27 | return A[p]; 28 | } 29 | sr::nth_element(A | srv::drop(p) | srv::take(r + 1), A.begin() + (p + r + 1) / 2); 30 | T x = A[(p + r + 1) / 2]; 31 | size_t q = partition(A, p, r, x); 32 | size_t k = q - p + 1; 33 | if (i == k) { 34 | return A[q]; 35 | } else if (i < k) { 36 | return Select(A, p, q - 1, i); 37 | } else { 38 | return Select(A, q + 1, r, i - k); 39 | } 40 | } 41 | 42 | int main() { 43 | std::vector v {4, 2, 1, 5, 3, 6}; 44 | std::cout << Select(v, 0, v.size() - 1, 4); 45 | 46 | 47 | } -------------------------------------------------------------------------------- /10/10.4-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct BinaryTreeNode { 7 | T key; 8 | std::unique_ptr> left; 9 | std::unique_ptr> right; 10 | 11 | BinaryTreeNode(const T& key) : key {key} {} 12 | }; 13 | 14 | template 15 | struct BinaryTree { 16 | std::unique_ptr> root; 17 | 18 | }; 19 | 20 | template 21 | std::ostream& operator<<(std::ostream& os, BinaryTreeNode* node) { 22 | if (node) { 23 | os << node->left.get(); 24 | os << node->key << ' '; 25 | os << node->right.get(); 26 | } 27 | return os; 28 | } 29 | 30 | template 31 | std::ostream& operator<<(std::ostream& os, const BinaryTree& tree) { 32 | os << tree.root.get(); 33 | return os; 34 | } 35 | 36 | int main() { 37 | BinaryTree t; 38 | auto n1 = std::make_unique>(1); 39 | auto n2 = std::make_unique>(2); 40 | auto n3 = std::make_unique>(3); 41 | 42 | t.root = std::move(n1); 43 | t.root->left = std::move(n2); 44 | t.root->right = std::move(n3); 45 | 46 | std::cout << t; 47 | 48 | } -------------------------------------------------------------------------------- /21/21.3-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class Node { 5 | T element; 6 | Node* parent = this; 7 | std::size_t rank = 0; 8 | 9 | public: 10 | Node(const T& element) : element(element) {} 11 | }; 12 | 13 | template 14 | Node MakeSet(const T& element) { 15 | Node node(element); 16 | return node; 17 | } 18 | 19 | template 20 | void Link(Node* x, Node* y) { 21 | if (!x || !y) { 22 | return; 23 | } 24 | if (x->rank > y->rank) { 25 | y->parent = x; 26 | } else { 27 | x->parent = y; 28 | if (x->rank == y->rank) { 29 | y->rank++; 30 | } 31 | } 32 | } 33 | 34 | template 35 | void Union(Node* x, Node* y) { 36 | Link(FindSet(x), FindSet(y)); 37 | } 38 | 39 | template 40 | Node* FindSet(Node* x) { 41 | if (!x) { 42 | return nullptr; 43 | } 44 | auto root = x; 45 | while (root->parent != root) { 46 | root = root->parent; 47 | } 48 | while (x->parent != root) { 49 | auto parent = x->parent; 50 | x->parent = root; 51 | x = parent; 52 | } 53 | return root; 54 | } 55 | 56 | int main() { 57 | 58 | } -------------------------------------------------------------------------------- /15/15.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int MemoizedCutRodAux(const std::vector& p, size_t n, std::vector& r, std::vector& s) { 9 | if (r[n] >= 0) { 10 | return r[n]; 11 | } 12 | int& q = r[n]; 13 | if (n == 0) { 14 | q = 0; 15 | } else { 16 | q = std::numeric_limits::lowest(); 17 | for (size_t i = 1; i <= n; i++) { 18 | auto val = MemoizedCutRodAux(p, n - i, r, s); 19 | if (q < p[i] + val) { 20 | q = p[i] + val; 21 | s[n] = i; 22 | } 23 | } 24 | } 25 | return q; 26 | } 27 | 28 | int MemoizedCutRod(const std::vector& p, size_t n) { 29 | std::vector r (n + 1, std::numeric_limits::lowest()); 30 | std::vector s (n + 1); 31 | auto val = MemoizedCutRodAux(p, n, r, s); 32 | while (n) { 33 | std::cout << s[n] << ' '; 34 | n -= s[n]; 35 | } 36 | std::cout << '\n'; 37 | return val; 38 | } 39 | 40 | 41 | int main() { 42 | std::vector p {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30}; 43 | std::cout << MemoizedCutRod(p, 10) << '\n'; 44 | } -------------------------------------------------------------------------------- /15/15.4-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Dir { 8 | upleft, 9 | up, 10 | left, 11 | }; 12 | 13 | template 14 | int LCSLength(const std::vector& X, const std::vector& Y) { 15 | size_t m = X.size(), n = Y.size(); 16 | auto X_ = X, Y_ = Y; 17 | if (m < n) { 18 | std::swap(X_, Y_); 19 | std::swap(m, n); // now m > n 20 | } 21 | std::vector curr(n + 1); 22 | int prev = 0; 23 | 24 | for (size_t i = 0; i <= m; i++) { 25 | prev = curr[0]; 26 | for (size_t j = 0; j <= n; j++) { 27 | int cache = curr[j]; 28 | if (i == 0 || j == 0) { 29 | curr[j] = 0; 30 | } else if (X_[i - 1] == Y_[j - 1]){ 31 | curr[j] = prev + 1; 32 | } else { 33 | curr[j] = std::max(curr[j], curr[j - 1]); 34 | } 35 | prev = cache; 36 | } 37 | } 38 | 39 | return curr[n]; 40 | } 41 | 42 | int main() { 43 | std::vector X = {'A', 'B', 'C', 'B', 'D', 'A', 'B'}; 44 | std::vector Y = {'B', 'D', 'C', 'A', 'B', 'A'}; 45 | std::cout << LCSLength(X, Y); 46 | 47 | 48 | } -------------------------------------------------------------------------------- /5/5.4.4_online_hiring_problem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::mt19937 gen(std::random_device{}()); 11 | 12 | namespace sr = std::ranges; 13 | 14 | int main() { 15 | constexpr size_t N = 100; 16 | constexpr size_t trials = 10000; 17 | std::vector v (N); 18 | std::iota(v.begin(), v.end(), 1); 19 | 20 | for (size_t K = 1; K < N; K++) { 21 | size_t total_best_score = 0; 22 | for (size_t t = 0; t < trials; t++) { 23 | auto u = v; 24 | sr::shuffle(u, gen); 25 | size_t best_score = 0; 26 | for (size_t i = 0; i < K; i++) { 27 | best_score = std::max(best_score, u[i]); 28 | } 29 | for (size_t i = K; i < N; i++) { 30 | if (u[i] > best_score) { 31 | total_best_score += u[i]; 32 | break; 33 | } 34 | } 35 | } 36 | std::cout << "Average best score with K " << K << " and N " << N << " : " 37 | << static_cast(total_best_score) / static_cast(trials) << '\n'; 38 | } 39 | } -------------------------------------------------------------------------------- /27/27.1_the_basics_of_dynamic_multithreading.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace crn = std::chrono; 8 | 9 | std::size_t Fib(std::size_t n) { 10 | if (n <= 1) { 11 | return n; 12 | } else { 13 | auto x = Fib(n - 1); 14 | auto y = Fib(n - 2); 15 | return x + y; 16 | } 17 | } 18 | 19 | void PFib(std::size_t n, std::size_t& result) { 20 | if (n <= 1) { 21 | result += n; 22 | } else { 23 | std::jthread t1(PFib, n - 1, std::ref(result)); 24 | PFib(n - 2, result); 25 | } 26 | } 27 | 28 | int main() { 29 | std::size_t N = 0; 30 | 31 | std::cin >> N; 32 | 33 | auto t1 = crn::steady_clock::now(); 34 | std::cout << Fib(N) << '\n'; 35 | auto t2 = crn::steady_clock::now(); 36 | auto dt1 = crn::duration_cast(t2 - t1); 37 | std::cout << "Fib : " << dt1.count() << "us\n"; 38 | std::size_t res = 0; 39 | auto t3 = crn::steady_clock::now(); 40 | PFib(N, res); 41 | std::cout << res << '\n'; 42 | auto t4 = crn::steady_clock::now(); 43 | auto dt2 = crn::duration_cast(t4 - t3); 44 | std::cout << "PFib : " << dt2.count() << "us\n"; 45 | } -------------------------------------------------------------------------------- /4/4.1-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int maxSubArray(const std::vector& nums) { 11 | if (nums.empty()) return 0; 12 | int runningSum = 0, maxSum = nums[0]; 13 | for (auto n : nums) { 14 | runningSum += n; 15 | maxSum = std::max(runningSum, maxSum); 16 | runningSum = std::max(0, runningSum); 17 | } 18 | return maxSum; 19 | } 20 | 21 | int main() { 22 | assert(maxSubArray(std::vector({-1})) == -1); 23 | assert(maxSubArray(std::vector({-2, 1, -3, 4, -1, 2, 1, -5, 4})) == 6); 24 | assert(maxSubArray(std::vector({})) == 0); 25 | 26 | constexpr int SIZE = 10'000'000; 27 | std::vector v (SIZE * 2); 28 | std::iota(v.begin(), v.end(), -SIZE); 29 | std::shuffle(v.begin(), v.end(), std::mt19937(std::random_device{}())); 30 | 31 | namespace crn = std::chrono; 32 | auto begin = crn::steady_clock::now(); 33 | auto n = maxSubArray(v); 34 | auto end = crn::steady_clock::now(); 35 | auto diff = crn::duration_cast(end - begin); 36 | assert(diff.count() < 1000); 37 | std::cout << "OK"; 38 | 39 | return EXIT_SUCCESS; 40 | } -------------------------------------------------------------------------------- /12/12.1-4_.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct BinaryTreeNode { 8 | T key; 9 | std::unique_ptr> left; 10 | std::unique_ptr> right; 11 | 12 | BinaryTreeNode(const T& key) : key {key} {} 13 | }; 14 | 15 | template 16 | struct BinaryTree { 17 | std::unique_ptr> root; 18 | 19 | }; 20 | 21 | template 22 | std::ostream& operator<<(std::ostream& os, BinaryTreeNode* node) { 23 | if (node) { 24 | // postorder 25 | os << node->left.get(); 26 | os << node->right.get(); 27 | os << node->key << ' '; 28 | } 29 | return os; 30 | } 31 | 32 | template 33 | std::ostream& operator<<(std::ostream& os, const BinaryTree& tree) { 34 | os << tree.root.get(); 35 | return os; 36 | } 37 | 38 | int main() { 39 | BinaryTree t; 40 | auto n1 = std::make_unique>(1); 41 | auto n2 = std::make_unique>(2); 42 | auto n3 = std::make_unique>(3); 43 | 44 | t.root = std::move(n1); 45 | t.root->left = std::move(n2); 46 | t.root->right = std::move(n3); 47 | 48 | std::cout << t; 49 | 50 | } -------------------------------------------------------------------------------- /7/7.3_a_randomized_version_of_quicksort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | std::mt19937 gen(std::random_device{}()); 10 | 11 | template 12 | size_t partition(std::vector& A, size_t p, size_t r) { 13 | T x = A[r]; 14 | size_t i = p; 15 | for (size_t j = p; j < r; j++) { 16 | if (A[j] <= x) { 17 | std::swap(A[i], A[j]); 18 | i++; 19 | } 20 | } 21 | std::swap(A[i], A[r]); 22 | return i; 23 | } 24 | 25 | template 26 | size_t randomizedPartition(std::vector& A, size_t p, size_t r) { 27 | std::uniform_int_distribution<> dst (p, r); 28 | size_t i = dst(gen); 29 | std::swap(A[i], A[r]); 30 | return partition(A, p, r); 31 | } 32 | 33 | template 34 | void randomizedQuickSort(std::vector& A, size_t p, size_t r) { 35 | if (p < r && r < A.size()) { 36 | size_t q = randomizedPartition(A, p, r); 37 | randomizedQuickSort(A, p, q - 1); 38 | randomizedQuickSort(A, q + 1, r); 39 | } 40 | } 41 | 42 | int main() { 43 | std::vector v {3, 2, 6, 1, 5, 4}; 44 | randomizedQuickSort(v, 0, v.size() - 1); 45 | assert(sr::is_sorted(v)); 46 | } -------------------------------------------------------------------------------- /12/12.1-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct BinaryTreeNode { 8 | T key; 9 | std::unique_ptr> left; 10 | std::unique_ptr> right; 11 | 12 | BinaryTreeNode(const T& key) : key {key} {} 13 | }; 14 | 15 | template 16 | struct BinaryTree { 17 | std::unique_ptr> root; 18 | 19 | }; 20 | 21 | template 22 | std::ostream& operator<<(std::ostream& os, BinaryTreeNode* node) { 23 | if (node) { 24 | // preorder 25 | os << node->key << ' '; 26 | os << node->left.get(); 27 | os << node->right.get(); 28 | } 29 | return os; 30 | } 31 | 32 | template 33 | std::ostream& operator<<(std::ostream& os, const BinaryTree& tree) { 34 | os << tree.root.get(); 35 | return os; 36 | } 37 | 38 | int main() { 39 | BinaryTree t; 40 | auto n1 = std::make_unique>(1); 41 | auto n2 = std::make_unique>(2); 42 | auto n3 = std::make_unique>(3); 43 | 44 | t.root = std::move(n1); 45 | t.root->left = std::move(n2); 46 | t.root->right = std::move(n3); 47 | 48 | std::cout << t; 49 | 50 | } -------------------------------------------------------------------------------- /12/12.1_what_is_binary_search_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct BinaryTreeNode { 8 | T key; 9 | std::unique_ptr> left; 10 | std::unique_ptr> right; 11 | 12 | BinaryTreeNode(const T& key) : key {key} {} 13 | }; 14 | 15 | template 16 | struct BinaryTree { 17 | std::unique_ptr> root; 18 | 19 | }; 20 | 21 | template 22 | std::ostream& operator<<(std::ostream& os, BinaryTreeNode* node) { 23 | if (node) { 24 | os << node->left.get(); 25 | os << node->key << ' '; 26 | os << node->right.get(); 27 | } 28 | return os; 29 | } 30 | 31 | template 32 | std::ostream& operator<<(std::ostream& os, const BinaryTree& tree) { 33 | os << tree.root.get(); 34 | return os; 35 | } 36 | 37 | int main() { 38 | BinaryTree t; 39 | auto n1 = std::make_unique>(1); 40 | auto n2 = std::make_unique>(2); 41 | auto n3 = std::make_unique>(3); 42 | 43 | t.root = std::move(n1); 44 | t.root->left = std::move(n2); 45 | t.root->right = std::move(n3); 46 | 47 | std::cout << t; 48 | 49 | } -------------------------------------------------------------------------------- /15/15-11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | double InventoryPlanning(size_t n, const std::vector& d, double c, size_t m, const std::vector& h) { 9 | auto D = std::accumulate(d.begin(), d.end(), 0ul); 10 | assert(h.size() == D); 11 | std::vector> cost (n, std::vector(D + 1)); 12 | for (size_t s = 0; s <= D; s++) { 13 | auto f = std::max(static_cast(d[n - 1]) - static_cast(s), 0); 14 | cost[n - 1][s] = c * std::max(f - static_cast(m), 0) + h[s + f - d[n]]; 15 | } 16 | auto U = d[n - 1]; 17 | for (size_t k = n - 2; k < n; k--) { 18 | U += d[k]; 19 | for (size_t s = 0; s <= D; s++) { 20 | cost[k][s] = std::numeric_limits::max(); 21 | for (int f = std::max(static_cast(d[k]) - static_cast(s), 0); f <= U - s; f++) { 22 | auto v = cost[k + 1][s + f - d[k]] + c * std::max(f - static_cast(m), 0) + h[s + f - d[k]]; 23 | if (v < cost[k][s]) { 24 | cost[k][s] = v; 25 | } 26 | } 27 | } 28 | } 29 | 30 | return cost[0][0]; 31 | } 32 | 33 | 34 | int main() { 35 | 36 | } -------------------------------------------------------------------------------- /15/15.4-5_6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sr = std::ranges; 11 | 12 | template 13 | std::vector LongestIncreasingSubsequence(const std::vector& X) { 14 | assert(!X.empty()); 15 | std::vector> LIS; 16 | std::vector endpoints; 17 | LIS.push_back(std::vector({X[0]})); 18 | endpoints.push_back(X[0]); 19 | 20 | for (size_t i = 1; i < X.size(); i++) { 21 | auto insertionPoint = sr::lower_bound(endpoints, X[i]); 22 | if (insertionPoint == endpoints.end()) { 23 | LIS.push_back(LIS.back()); 24 | LIS.back().push_back(X[i]); 25 | endpoints.push_back(X[i]); 26 | } else { 27 | *insertionPoint = X[i]; 28 | int index = std::distance(endpoints.begin(), insertionPoint); 29 | LIS[index].back() = X[i]; 30 | } 31 | } 32 | return LIS.back(); 33 | } 34 | 35 | int main() { 36 | std::vector v {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; 37 | auto LIS = LongestIncreasingSubsequence(v); 38 | for (auto n : LIS) { 39 | std::cout << n << ' '; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /22/22.4-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class Graph { 10 | std::vector> adj; 11 | public: 12 | Graph() : adj(n) { 13 | } 14 | 15 | std::vector TopologicalSort() { 16 | std::stack firstNodes; 17 | std::vector topSort; 18 | std::vector indegrees(n); 19 | for (std::size_t src = 0; src < n; ++src) { 20 | for (auto dst : adj[src]) { 21 | ++indegrees[dst]; 22 | } 23 | } 24 | for (std::size_t i = 0; i < n; ++i) { 25 | if (!indegrees[i]) { 26 | firstNodes.push(i); 27 | } 28 | } 29 | while (!firstNodes.empty()) { 30 | auto curr = firstNodes.top(); 31 | firstNodes.pop(); 32 | topSort.push_back(curr); 33 | for (auto dst : adj[curr]) { 34 | --indegrees[dst]; 35 | if (!indegrees[dst]) { 36 | firstNodes.push(dst); 37 | } 38 | } 39 | } 40 | 41 | return topSort; 42 | } 43 | }; 44 | 45 | 46 | int main() { 47 | 48 | } 49 | -------------------------------------------------------------------------------- /17/17.4_dynamic_table.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace crn = std::chrono; 8 | 9 | int main() { 10 | constexpr std::size_t SIZE = 100'000; 11 | std::mt19937 gen(std::random_device{}()); 12 | std::bernoulli_distribution dist(0.5); 13 | 14 | std::vector v; 15 | 16 | auto t1 = crn::steady_clock::now(); 17 | for (std::size_t i = 0; i < SIZE; i++) { 18 | v.push_back(i); 19 | } 20 | auto t2 = crn::steady_clock::now(); 21 | auto d1 = crn::duration_cast(t2 - t1); 22 | std::cout << d1.count() << "ms\n"; 23 | t1 = crn::steady_clock::now(); 24 | for (std::size_t i = 0; i < SIZE; i++) { 25 | v.pop_back(); 26 | } 27 | t2 = crn::steady_clock::now(); 28 | d1 = crn::duration_cast(t2 - t1); 29 | std::cout << d1.count() << "ms\n"; 30 | t1 = crn::steady_clock::now(); 31 | for (std::size_t i = 0; i < SIZE; i++) { 32 | if (dist(gen) || v.empty()) { 33 | v.push_back(i); 34 | } else { 35 | v.pop_back(); 36 | } 37 | } 38 | t2 = crn::steady_clock::now(); 39 | d1 = crn::duration_cast(t2 - t1); 40 | std::cout << d1.count() << "ms\n"; 41 | 42 | } -------------------------------------------------------------------------------- /31/31.9-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::mt19937 gen(std::random_device{}()); 9 | 10 | std::unordered_set PollardRho(std::size_t n, std::size_t B) { 11 | std::size_t i = 1; 12 | std::uniform_int_distribution<> dist(0, n - 1); 13 | auto x = dist(gen); 14 | std::size_t y = x; 15 | std::size_t k = B; 16 | std::unordered_set res; 17 | while (i <= n) { 18 | std::size_t P = 1; 19 | for (std::size_t k = 1; k <= B; k++) { 20 | x = (x * x - 1) % n; 21 | P *= (y - x); 22 | } 23 | i += B; 24 | auto d = std::gcd(P, n); 25 | if (d != 1 && d != n) { 26 | res.insert(d); 27 | } 28 | if (i >= k) { 29 | y = x; 30 | k *= 2; 31 | } 32 | } 33 | return res; 34 | } 35 | 36 | int main() { 37 | auto factors = PollardRho(1328789, 1); 38 | for (auto factor : factors) { 39 | std::cout << factor << ' '; 40 | } 41 | std::cout << '\n'; 42 | auto factors2 = PollardRho(1328789, 10); 43 | for (auto factor : factors2) { 44 | std::cout << factor << ' '; 45 | } 46 | std::cout << '\n'; 47 | 48 | } -------------------------------------------------------------------------------- /15/15.4-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Dir { 8 | upleft, 9 | up, 10 | left, 11 | }; 12 | 13 | template 14 | int MemoizedLCSLengthAux(std::vector>& C, 15 | const std::vector& X, const std::vector& Y, size_t i, size_t j) { 16 | if (C[i][j] >= 0) { 17 | return C[i][j]; 18 | } 19 | int& ret = C[i][j]; 20 | if (i == 0 || j == 0) { 21 | ret = 0; 22 | return ret; 23 | } 24 | if (X[i] == Y[j]) { 25 | ret = MemoizedLCSLengthAux(C, X, Y, i - 1, j - 1) + 1; 26 | return ret; 27 | } 28 | ret = std::max(MemoizedLCSLengthAux(C, X, Y, i - 1, j), MemoizedLCSLengthAux(C, X, Y, i, j - 1)); 29 | return ret; 30 | } 31 | 32 | template 33 | int MemoizedLCSLength(const std::vector& X, const std::vector& Y) { 34 | std::vector> C (X.size() + 1, std::vector(Y.size() + 1, -1)); 35 | MemoizedLCSLengthAux(C, X, Y, X.size(), Y.size()); 36 | return C[X.size()][Y.size()]; 37 | } 38 | 39 | int main() { 40 | std::vector X = {'A', 'B', 'C', 'B', 'D', 'A', 'B'}; 41 | std::vector Y = {'B', 'D', 'C', 'A', 'B', 'A'}; 42 | std::cout << MemoizedLCSLength(X, Y); 43 | 44 | 45 | } -------------------------------------------------------------------------------- /35/35-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::vector> FirstFit(const std::vector& S) { 8 | std::map B; 9 | std::vector> L; 10 | for (auto s : S) { 11 | auto it = B.lower_bound(s); 12 | if (it == B.end()) { 13 | std::vector L_b {s}; 14 | L.push_back(std::move(L_b)); 15 | B[1 - s] = L.size() - 1; 16 | } else { 17 | auto [e, j] = *it; 18 | L[j].push_back(s); 19 | B.erase(e); 20 | if (e > s) { 21 | B[e - s] = j; 22 | } 23 | } 24 | } 25 | return L; 26 | } 27 | 28 | int main() { 29 | std::mt19937 gen(std::random_device{}()); 30 | std::uniform_real_distribution<> dist(0.0001, 0.9999); 31 | constexpr std::size_t n = 20; 32 | std::vector S; 33 | S.reserve(n); 34 | for (std::size_t i = 0; i < n; i++) { 35 | S.push_back(dist(gen)); 36 | } 37 | 38 | auto FFit = FirstFit(S); 39 | for (const auto& bin : FFit) { 40 | for (auto num : bin) { 41 | std::cout << num << ' '; 42 | } 43 | std::cout << '\n'; 44 | } 45 | std::cout << '\n'; 46 | 47 | } -------------------------------------------------------------------------------- /16/16.1-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | std::pair>, std::vector>> 10 | DynamicActivitySelect(std::vector>& intervals) { 11 | sr::sort(intervals, [](auto& a, auto& b) {return std::get<1>(a) < std::get<1>(b);}); 12 | size_t n = intervals.size(); 13 | std::vector> c(n + 2, std::vector(n + 2)); 14 | std::vector> a(n + 2, std::vector(n + 2)); 15 | for (size_t l = 2; l <= n + 1; l++) { 16 | for (size_t i = 0; i <= n - l + 1; i++) { 17 | size_t j = i + l; 18 | size_t k = j - 1; 19 | while (std::get<1>(intervals[i]) < std::get<1>(intervals[k])) { 20 | if (std::get<1>(intervals[i]) <= std::get<0>(intervals[k]) && std::get<1>(intervals[k]) <= std::get<0>(intervals[j]) 21 | && c[i][k] + c[k][j] + std::get<2>(intervals[k]) > c[i][j]) { 22 | c[i][j] = c[i][k] + c[k][j] + std::get<2>(intervals[k]); 23 | a[i][j] = k; 24 | } 25 | k--; 26 | } 27 | } 28 | } 29 | return {c, a}; 30 | } 31 | 32 | 33 | int main() { 34 | } 35 | -------------------------------------------------------------------------------- /31/31.4_solving_modular_linear_equations.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::tuple ExtendedEuclid(std::size_t a, std::size_t b) { 7 | if (!b) { 8 | return {a, 1, 0}; 9 | } else { 10 | auto [d_, x_, y_] = ExtendedEuclid(b, a % b); 11 | std::size_t d = d_; 12 | int x = y_; 13 | int y = x_ - static_cast(a / b) * y_; 14 | return {d, x, y}; 15 | } 16 | } 17 | 18 | std::size_t mod(int a, std::size_t n) { 19 | if (a >= 0) { 20 | return a % n; 21 | } else { 22 | return n - ((-a) % n); 23 | } 24 | } 25 | 26 | std::vector ModularLinearEquationSolver(std::size_t a, int b, std::size_t n) { 27 | auto [d, x_, y_] = ExtendedEuclid(a, n); 28 | if ((b % d) == 0) { 29 | std::size_t x_0 = mod(x_ * b / static_cast(d), n); 30 | std::vector res; 31 | for (std::size_t i = 0; i < d; i++) { 32 | res.push_back((x_0 + i * (n / d)) % n); 33 | } 34 | return res; 35 | } else { 36 | return {}; 37 | } 38 | } 39 | 40 | int main() { 41 | auto ans = ModularLinearEquationSolver(14, 30, 100); 42 | for (auto x : ans) { 43 | std::cout << x << ' '; 44 | } 45 | std::cout << '\n'; 46 | 47 | } -------------------------------------------------------------------------------- /9/9.3-8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | std::optional findMedian(const std::vector& A, const std::vector& B, size_t low, size_t high) { 10 | if (low > high) { 11 | return {}; 12 | } else { 13 | size_t k = (low + high) / 2; 14 | if (k == A.size() - 1 && A[A.size() - 1] <= B[0]) { 15 | return A[A.size() - 1]; 16 | } else if (k < A.size() - 1 && B[B.size() - 1 - k] <= A[k] && A[k] <= B[B.size() - k]) { 17 | return A[k]; 18 | } else if (A[k] > B[B.size() - k]) { 19 | return findMedian(A, B, low, k - 1); 20 | } else { 21 | return findMedian(A, B, k + 1, high); 22 | } 23 | } 24 | } 25 | 26 | 27 | template 28 | T twoArrayMedian(const std::vector& A, const std::vector& B) { 29 | T median = findMedian(A, B, 0, A.size() - 1).value(); 30 | if (!median) { 31 | median = findMedian(B, A, 0, B.size() - 1).value(); 32 | } 33 | return median; 34 | } 35 | 36 | int main() { 37 | std::vector A (10); 38 | std::iota(A.begin(), A.end(), 4); 39 | std::vector B (10); 40 | std::iota(B.begin(), B.end(), 8); 41 | std::cout << twoArrayMedian(A, B); 42 | 43 | } -------------------------------------------------------------------------------- /27/27-6_d.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | 11 | std::mt19937 gen(std::random_device{}()); 12 | 13 | template 14 | size_t partition(std::vector& A, size_t p, size_t r) { 15 | T x = A[r]; 16 | size_t i = p; 17 | for (size_t j = p; j < r; j++) { 18 | if (A[j] <= x) { 19 | std::swap(A[i], A[j]); 20 | i++; 21 | } 22 | } 23 | std::swap(A[i], A[r]); 24 | return i; 25 | } 26 | 27 | template 28 | size_t randomizedPartition(std::vector& A, size_t p, size_t r) { 29 | std::uniform_int_distribution<> dst (p, r); 30 | size_t i = dst(gen); 31 | std::swap(A[i], A[r]); 32 | return partition(A, p, r); 33 | } 34 | 35 | template 36 | void PRandomizedQuickSort(std::vector& A, size_t p, size_t r) { 37 | if (p < r && r < A.size()) { 38 | size_t q = randomizedPartition(A, p, r); 39 | std::jthread t (&PRandomizedQuickSort, std::ref(A), p, q - 1); 40 | PRandomizedQuickSort(A, q + 1, r); 41 | } 42 | } 43 | 44 | int main() { 45 | std::vector v {3, 2, 6, 1, 5, 4}; 46 | PRandomizedQuickSort(v, 0, v.size() - 1); 47 | assert(sr::is_sorted(v)); 48 | } -------------------------------------------------------------------------------- /9/9-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | namespace srv = std::ranges::views; 11 | 12 | template 13 | std::vector Select(std::vector& A, size_t i) { 14 | if (i >= A.size() / 2) { 15 | sr::nth_element(A, A.begin() + i); 16 | std::vector B (A.begin(), A.begin() + i); 17 | return B; 18 | } else { 19 | size_t m = A.size() / 2; 20 | for (size_t j = 0; j < m; j++) { 21 | if (A[j] < A[j + m]) { 22 | std::swap(A[j], A[j + m]); 23 | } 24 | } 25 | sr::nth_element(A | srv::drop(m), A.begin() + m + i); 26 | sr::nth_element(A, A.begin() + i); 27 | std::vector B; 28 | for (size_t j = 0; j < i; j++) { 29 | B.push_back(A[j]); 30 | B.push_back(A[m + j]); 31 | } 32 | sr::nth_element(B, B.begin() + i); 33 | std::vector C (std::make_move_iterator(B.begin()), std::make_move_iterator(B.begin() + i)); 34 | return C; 35 | } 36 | } 37 | 38 | int main() { 39 | std::vector v {7, 9, 1, 3, 6, 5, 8, 4, 10, 2}; 40 | auto w = Select(v, 3); 41 | for (auto n : w) { 42 | std::cout << n << ' '; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /9/9.1-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sr = std::ranges; 9 | 10 | template 11 | T secondSmallest(const std::vector& A) { 12 | assert(T.size() >= 2); 13 | std::vector B = A; 14 | std::vector> total_results; 15 | std::vector C; 16 | while (B.size() > 1) { 17 | C.clear(); 18 | for (size_t i = 0; i < B.size(); i += 2) { 19 | if (i == B.size() - 1) { 20 | C.push_back(B[i]); 21 | total_results.emplace_back(B[i], B[i]); 22 | } else if (B[i] < B[i + 1]) { 23 | C.push_back(B[i]); 24 | total_results.emplace_back(B[i], B[i + 1]); 25 | } else { // B[i] >= B[i + 1] 26 | C.push_back(B[i + 1]); 27 | total_results.emplace_back(B[i + 1], B[i]); 28 | } 29 | } 30 | B = C; 31 | } 32 | T minElement = C[0]; 33 | C.clear(); 34 | for (const auto& [small, big] : total_results) { 35 | if (small == minElement) { 36 | C.push_back(big); 37 | } 38 | } 39 | return *sr::min_element(C); 40 | } 41 | 42 | int main() { 43 | std::vector v{1, 5, 3, 2, 6}; 44 | std::cout << secondSmallest(v); 45 | 46 | } -------------------------------------------------------------------------------- /21/21-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class Node { 5 | T element; 6 | Node* parent = this; 7 | std::size_t rank = 0; 8 | std::size_t d = 0; 9 | 10 | public: 11 | Node(const T& element) : element(element) {} 12 | }; 13 | 14 | template 15 | Node MakeTree(const T& element) { 16 | Node node(element); 17 | return node; 18 | } 19 | 20 | template 21 | Node* FindRoot(Node* v) { 22 | if (v->parent != v->parent->parent) { 23 | auto y = v->parent; 24 | v->parent = FindRoot(y); 25 | v->d += y->d; 26 | } 27 | return v->parent; 28 | } 29 | 30 | template 31 | std::size_t FindDepth(Node* v) { 32 | FindRoot(v); 33 | if (v == v->parent) { 34 | return v->d; 35 | } else { 36 | return v->d + v->parent->d; 37 | } 38 | } 39 | 40 | template 41 | void Graft(Node* r, Node* v) { 42 | auto rr = FindRoot(r); 43 | auto vr = FindRoot(v); 44 | auto z = FindDepth(v); 45 | if (rr->rank > vr->rank) { 46 | vr->parent = rr; 47 | rr->d += z + 1; 48 | vr->d -= rr->d; 49 | } else { 50 | rr->parent = vr; 51 | rr->d += z + 1 - vr->d; 52 | if (rr->rank == vr->rank) { 53 | vr->rank++; 54 | } 55 | } 56 | } 57 | 58 | int main() { 59 | 60 | } -------------------------------------------------------------------------------- /9/9.2_selection_in_expected_linear_time.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::mt19937 gen(std::random_device{}()); 7 | 8 | template 9 | size_t partition(std::vector& A, size_t p, size_t r) { 10 | T x = A[r]; 11 | size_t i = p; 12 | for (size_t j = p; j < r; j++) { 13 | if (A[j] <= x) { 14 | std::swap(A[i], A[j]); 15 | i++; 16 | } 17 | } 18 | std::swap(A[i], A[r]); 19 | return i; 20 | } 21 | 22 | template 23 | size_t randomizedPartition(std::vector& A, size_t p, size_t r) { 24 | std::uniform_int_distribution<> dst (p, r); 25 | size_t i = dst(gen); 26 | std::swap(A[i], A[r]); 27 | return partition(A, p, r); 28 | } 29 | 30 | template 31 | T randomizedSelect(std::vector& A, size_t p, size_t r, size_t i) { 32 | if (p == r) { 33 | return A[p]; 34 | } 35 | size_t q = randomizedPartition(A, p, r); 36 | size_t k = q - p + 1; 37 | if (i == k) { 38 | return A[q]; 39 | } else if (i < k) { 40 | return randomizedSelect(A, p, q - 1, i); 41 | } else { 42 | return randomizedSelect(A, q + 1, r, i - k); 43 | } 44 | } 45 | 46 | int main() { 47 | std::vector v {4, 2, 1, 5, 3, 6}; 48 | std::cout << randomizedSelect(v, 0, v.size() - 1, v.size() / 2); 49 | 50 | } -------------------------------------------------------------------------------- /22/22.3_depth_first_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Color { 8 | White, 9 | Gray, 10 | Black 11 | }; 12 | 13 | using info_t = std::tuple; 14 | 15 | template 16 | class Graph { 17 | std::vector> adj; 18 | public: 19 | Graph() : adj(n) { 20 | } 21 | 22 | std::vector infos; 23 | 24 | void DFSVisit(std::size_t u, std::size_t& time) { 25 | time++; 26 | std::get<1>(infos[u]) = time; 27 | std::get<0>(infos[u]) = Color::Gray; 28 | for (auto v : adj[u]) { 29 | if (std::get<0>(infos[v]) == Color::White) { 30 | std::get<3>(infos[v]) = u; 31 | DFSVisit(v, time); 32 | } 33 | } 34 | std::get<0>(infos[u]) = Color::Black; 35 | time++; 36 | std::get<2>(infos[u]) = time; 37 | } 38 | 39 | void DFS() { 40 | infos = std::vector(n, std::make_tuple(Color::White, 0, 0, -1)); 41 | std::size_t time = 0; 42 | for (std::size_t i = 0; i < n; i++) { 43 | if (std::get<0>(infos[i]) == Color::White) { 44 | DFSVisit(i, time); 45 | } 46 | } 47 | } 48 | }; 49 | 50 | 51 | int main() { 52 | 53 | } 54 | -------------------------------------------------------------------------------- /2/2_4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | size_t merge(std::vector& A, size_t p, size_t q, size_t r) { 8 | size_t i = p; 9 | size_t j = q; 10 | size_t count = 0; 11 | std::vector B (1 + r - p); 12 | size_t k = 0; 13 | while (i < q && j <= r) { 14 | if (A[i] < A[j]) { 15 | B[k++] = A[i++]; 16 | } else { 17 | B[k++] = A[j++]; 18 | count += q - i; 19 | } 20 | } 21 | while (i < q) { 22 | B[k++] = A[i++]; 23 | } 24 | while (j <= r) { 25 | B[k++] = A[j++]; 26 | } 27 | std::copy(B.begin(), B.end(), A.begin() + p); 28 | return count; 29 | } 30 | 31 | template 32 | size_t inversionsHelper(std::vector& A, size_t p, size_t r) { 33 | if (p < r) { 34 | size_t q = (p + r) / 2; 35 | size_t count = 0; 36 | count += inversionsHelper(A, p, q); 37 | count += inversionsHelper(A, q + 1, r); 38 | count += merge(A, p, q + 1, r); 39 | return count; 40 | } 41 | return 0; 42 | } 43 | 44 | template 45 | size_t inversions(std::vector& A) { 46 | return inversionsHelper(A, 0, A.size() - 1); 47 | } 48 | 49 | 50 | int main() { 51 | std::vector v {5, 4, 3, 2, 1}; 52 | std::cout << inversions(v); 53 | 54 | 55 | } -------------------------------------------------------------------------------- /10/10.1_stacks_and_queues.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct Stack { 9 | std::array data; 10 | size_t top = 0; 11 | }; 12 | 13 | template 14 | bool StackEmpty(const Stack& s) { 15 | return s.top == 0; 16 | } 17 | 18 | template 19 | void Push(Stack& s, const T& x) { 20 | s.data[s.top++] = x; 21 | } 22 | 23 | template 24 | T Pop(Stack& s) { 25 | if (StackEmpty(s)) { 26 | throw std::underflow_error("Stack underflow"); 27 | } else { 28 | return s.data[--s.second]; 29 | } 30 | } 31 | 32 | template 33 | struct Queue { 34 | std::array data; 35 | size_t head = 0; 36 | size_t tail = 0; 37 | }; 38 | 39 | template 40 | void Enqueue(Queue& q, const T& x) { 41 | q.data[q.tail] = x; 42 | if (q.tail == q.data.size() - 1) { 43 | q.tail = 0; 44 | } else { 45 | q.tail++; 46 | } 47 | } 48 | 49 | template 50 | void Dequeue(Queue& q) { 51 | T x = q.data[q.head]; 52 | if (q.head == q.data.size() - 1) { 53 | q.head = 0; 54 | } else { 55 | q.head++; 56 | } 57 | return x; 58 | } 59 | 60 | int main() { 61 | 62 | } -------------------------------------------------------------------------------- /9/9.2-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::mt19937 gen(std::random_device{}()); 7 | 8 | template 9 | size_t partition(std::vector& A, size_t p, size_t r) { 10 | T x = A[r]; 11 | size_t i = p; 12 | for (size_t j = p; j < r; j++) { 13 | if (A[j] <= x) { 14 | std::swap(A[i], A[j]); 15 | i++; 16 | } 17 | } 18 | std::swap(A[i], A[r]); 19 | return i; 20 | } 21 | 22 | template 23 | size_t randomizedPartition(std::vector& A, size_t p, size_t r) { 24 | std::uniform_int_distribution<> dst (p, r); 25 | size_t i = dst(gen); 26 | std::swap(A[i], A[r]); 27 | return partition(A, p, r); 28 | } 29 | 30 | template 31 | T randomizedSelectIterative(std::vector& A, size_t p, size_t r, size_t i) { 32 | while (true) { 33 | if (p == r) { 34 | return A[p]; 35 | } 36 | size_t q = randomizedPartition(A, p, r); 37 | size_t k = q - p + 1; 38 | if (i == k) { 39 | return A[q]; 40 | } else if (i < k) { 41 | r = q; 42 | } else { 43 | p = q; 44 | i -= k; 45 | } 46 | } 47 | } 48 | 49 | int main() { 50 | std::vector v {4, 2, 1, 5, 3, 6}; 51 | std::cout << randomizedSelectIterative(v, 0, v.size() - 1, v.size() / 2); 52 | 53 | } -------------------------------------------------------------------------------- /10/10.4-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct BinaryTreeNode { 8 | T key; 9 | std::unique_ptr> left; 10 | std::unique_ptr> right; 11 | 12 | BinaryTreeNode(const T& key) : key {key} {} 13 | }; 14 | 15 | template 16 | struct BinaryTree { 17 | std::unique_ptr> root; 18 | 19 | }; 20 | 21 | template 22 | std::ostream& operator<<(std::ostream& os, const BinaryTree& tree) { 23 | std::stack*> s; 24 | s.push(tree.root.get()); 25 | while (!s.empty()) { 26 | auto x = s.top(); 27 | while (x) { 28 | s.push(x->left.get()); 29 | x = s.top(); 30 | } 31 | s.pop(); 32 | if (!s.empty()) { 33 | x = s.top(); 34 | s.pop(); 35 | os << x->key << ' '; 36 | s.push(x->right.get()); 37 | } 38 | } 39 | return os; 40 | } 41 | 42 | int main() { 43 | BinaryTree t; 44 | auto n1 = std::make_unique>(1); 45 | auto n2 = std::make_unique>(2); 46 | auto n3 = std::make_unique>(3); 47 | 48 | t.root = std::move(n1); 49 | t.root->left = std::move(n2); 50 | t.root->right = std::move(n3); 51 | 52 | std::cout << t; 53 | 54 | } -------------------------------------------------------------------------------- /12/12.1-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct BinaryTreeNode { 8 | T key; 9 | std::unique_ptr> left; 10 | std::unique_ptr> right; 11 | 12 | BinaryTreeNode(const T& key) : key {key} {} 13 | }; 14 | 15 | template 16 | struct BinaryTree { 17 | std::unique_ptr> root; 18 | 19 | }; 20 | 21 | template 22 | std::ostream& operator<<(std::ostream& os, const BinaryTree& tree) { 23 | std::stack*> s; 24 | s.push(tree.root.get()); 25 | while (!s.empty()) { 26 | auto x = s.top(); 27 | while (x) { 28 | s.push(x->left.get()); 29 | x = s.top(); 30 | } 31 | s.pop(); 32 | if (!s.empty()) { 33 | x = s.top(); 34 | s.pop(); 35 | os << x->key << ' '; 36 | s.push(x->right.get()); 37 | } 38 | } 39 | return os; 40 | } 41 | 42 | int main() { 43 | BinaryTree t; 44 | auto n1 = std::make_unique>(1); 45 | auto n2 = std::make_unique>(2); 46 | auto n3 = std::make_unique>(3); 47 | 48 | t.root = std::move(n1); 49 | t.root->left = std::move(n2); 50 | t.root->right = std::move(n3); 51 | 52 | std::cout << t; 53 | 54 | } -------------------------------------------------------------------------------- /7/7.2-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | 11 | template 12 | size_t partition(std::vector& A, size_t p, size_t r) { 13 | T x = A[r]; 14 | size_t i = p; 15 | size_t equal_count = 0; 16 | for (size_t j = p; j < r; j++) { 17 | if (A[j] >= x) { 18 | std::swap(A[i], A[j]); 19 | i++; 20 | } 21 | } 22 | std::swap(A[i], A[r]); 23 | return i; 24 | } 25 | 26 | int main() { 27 | constexpr double alpha = 0.3; 28 | constexpr size_t trials = 1'000; 29 | constexpr size_t N = 1'000; 30 | 31 | std::vector v (N); 32 | std::iota(v.begin(), v.end(), 0); 33 | std::mt19937 gen(std::random_device{}()); 34 | 35 | size_t balanced_count = 0; 36 | for (size_t i = 0; i < trials; i++) { 37 | auto u = v; 38 | sr::shuffle(u, gen); 39 | size_t q = partition(u, 0, u.size() - 1); 40 | 41 | if (q < (1.0 - alpha) * N && q > (alpha) * N) { 42 | balanced_count++; 43 | } 44 | } 45 | 46 | std::cout << "Probability that the partition is balanced than (1-a)/a : " 47 | << static_cast(balanced_count) / static_cast(trials) << '\n'; 48 | std::cout << "1 - 2a : " << 1.0 - 2 * alpha << '\n'; 49 | 50 | } -------------------------------------------------------------------------------- /15/15.5_optimal_binary_search_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::pair>, std::vector>> 8 | OptimalBST(const std::vector& p, const std::vector& q) { 9 | size_t n = p.size(); 10 | std::vector> expect (n + 2, std::vector(n + 1)); 11 | std::vector> partialProbSum (n + 2, std::vector(n + 1)); 12 | std::vector> root (n + 1, std::vector(n + 1)); 13 | for (size_t i = 1; i <= n + 1; i++) { 14 | expect[i][i - 1] = q[i]; 15 | partialProbSum[i][i - 1] = q[i]; 16 | } 17 | for (size_t l = 1; l <= n; l++) { // l : length of chain 18 | for (size_t i = 1; i <= n - l + 1; i++) { // begin 19 | size_t j = i + l - 1; // end 20 | expect[i][j] = std::numeric_limits::max(); 21 | partialProbSum[i][j] = partialProbSum[i][j - 1] + p[j] + q[j]; 22 | for (size_t r = i; r <= j; r++) { // root 23 | double v = expect[i][r - 1] + expect[r + 1][j] + partialProbSum[i][j]; 24 | if (v < expect[i][j]) { 25 | expect[i][j] = v; 26 | root[i][j] = r; 27 | } 28 | } 29 | } 30 | } 31 | return {expect, root}; 32 | } 33 | 34 | int main() { 35 | 36 | } -------------------------------------------------------------------------------- /31/31-4_d.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::size_t ModularExponentiation(std::size_t a, std::size_t b, std::size_t n) { 10 | assert(n); 11 | std::size_t c = 0; 12 | std::size_t d = 1; 13 | auto k = std::bit_width(b); 14 | std::bitset<64> B(b); 15 | for (std::size_t i = k - 1; i < k; i--) { 16 | c *= 2; 17 | d = (d * d) % n; 18 | if (B[i]) { 19 | c++; 20 | d = (d * a) % n; 21 | } 22 | } 23 | return d; 24 | } 25 | 26 | bool isQuadraticResidue(std::size_t a, std::size_t p) { 27 | return ModularExponentiation(a, (p - 1) >> 1, p) == 1; 28 | } 29 | 30 | std::mt19937 gen(std::random_device{}()); 31 | 32 | std::size_t findNonQuadraticResidue(std::size_t p) { 33 | assert(p > 2 && (p & 1)); 34 | std::uniform_int_distribution<> dist(1, p - 1); 35 | while (true) { 36 | auto a = dist(gen); 37 | if (!isQuadraticResidue(a, p)) { 38 | return a; 39 | } 40 | } 41 | } 42 | 43 | int main() { 44 | std::cout << findNonQuadraticResidue(11) << '\n'; 45 | std::cout << findNonQuadraticResidue(11) << '\n'; 46 | std::cout << findNonQuadraticResidue(11) << '\n'; 47 | std::cout << findNonQuadraticResidue(11) << '\n'; 48 | std::cout << findNonQuadraticResidue(11) << '\n'; 49 | 50 | 51 | } -------------------------------------------------------------------------------- /5/5.4-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::mt19937 gen(std::random_device{}()); 10 | 11 | int main() { 12 | constexpr size_t N = 100; 13 | constexpr size_t trials = 1000; 14 | std::uniform_int_distribution<> toss(0, N - 1); 15 | size_t empty_bin_count = 0; 16 | size_t one_bin_count = 0; 17 | for (size_t t = 0; t < trials; t++) { 18 | std::vector bin(N); 19 | for (size_t i = 0; i < N; i++) { 20 | bin[toss(gen)] += 1; 21 | } 22 | for (auto balls : bin) { 23 | if (balls == 0) { 24 | empty_bin_count++; 25 | } else if (balls == 1) { 26 | one_bin_count++; 27 | } 28 | } 29 | } 30 | 31 | std::cout << "Expected number of empty bins : " << static_cast(empty_bin_count) / 32 | static_cast(trials) << '\n'; 33 | std::cout << "n ((n-1)/n)^n : " << (N * std::pow(static_cast(N - 1) / N, N)) << '\n'; 34 | std::cout << "Expected number of bins with exactly one ball : " << static_cast(one_bin_count) / 35 | static_cast(trials) << '\n'; 36 | std::cout << "n ((n-1)/n)^(n-1) : " << (N * std::pow(static_cast(N - 1) / N, N - 1)) << '\n'; 37 | 38 | } -------------------------------------------------------------------------------- /16/16-3_b.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | struct Graph { 10 | struct Edge { 11 | Edge(size_t source, size_t target, double weight) : source {source}, target {target}, weight {weight} {} 12 | size_t source; 13 | size_t target; 14 | double weight; 15 | }; 16 | 17 | size_t vertices; 18 | std::vector edges; 19 | 20 | explicit Graph (size_t n) : vertices {n} {} 21 | 22 | void addEdge(size_t source, size_t target, double weight) { 23 | assert(source < vertices && target < vertices && source != target && weight >= 0.0); 24 | edges.emplace_back(source, target, weight); 25 | } 26 | 27 | std::vector maximalAcyclicEdges() { 28 | sr::sort(edges, 29 | [](const auto &edge1, const auto &edge2) { return edge1.weight < edge2.weight; }); 30 | std::vector result; 31 | std::unordered_set currVertices; 32 | for (const auto& [source, target, weight] : edges) { 33 | if (!currVertices.contains(source) && !currVertices.contains(target)) { 34 | currVertices.insert(source); 35 | currVertices.insert(target); 36 | result.emplace_back(source, target, weight); 37 | } 38 | } 39 | return result; 40 | } 41 | 42 | }; 43 | 44 | 45 | int main() { 46 | } 47 | -------------------------------------------------------------------------------- /10/10.2-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct ListNode { 7 | T key; 8 | std::shared_ptr> next; 9 | ListNode(const T& key) : key {key} {} 10 | }; 11 | 12 | template 13 | struct List { 14 | private: 15 | std::shared_ptr> nil; 16 | public: 17 | List() { 18 | nil = std::make_shared>(T()); 19 | nil->next = nil; 20 | } 21 | 22 | void ListDelete(const T& k) { 23 | auto prev = nil; 24 | while (prev->next->key != k) { 25 | if (prev->next == nil) { 26 | throw std::runtime_error("Key does not exist"); 27 | } 28 | prev = prev->next; 29 | } 30 | prev->next = prev->next->next; 31 | } 32 | 33 | std::shared_ptr> ListSearch(const T& k) { 34 | auto x = nil->next; 35 | while (x != nil && x->key != k) { 36 | x = x->next; 37 | } 38 | if (x == nil) { 39 | return nullptr; 40 | } 41 | return x; 42 | } 43 | 44 | void ListInsert(const T& k) { 45 | auto x = std::make_shared>(k); 46 | x->next = nil->next; 47 | nil->next = x; 48 | } 49 | }; 50 | 51 | int main() { 52 | List l; 53 | l.ListInsert(1); 54 | assert(l.ListSearch(1)); 55 | l.ListInsert(2); 56 | l.ListInsert(3); 57 | l.ListDelete(2); 58 | assert(!l.ListSearch(2)); 59 | 60 | } -------------------------------------------------------------------------------- /10/10.3-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct GC { 9 | std::array prev; 10 | std::array next; 11 | std::array key = {0}; 12 | 13 | size_t free = 0; 14 | size_t head = 0; 15 | 16 | GC() { 17 | for (size_t i = 0; i < N; i++) { 18 | prev[i] = i - 1; 19 | next[i] = i + 1; 20 | } 21 | next[N - 1] = -1; 22 | } 23 | 24 | size_t AllocateObject() { 25 | if (free == -1) { 26 | throw std::runtime_error("out of space"); 27 | } else { 28 | size_t x = free; 29 | free = next[x]; 30 | return x; 31 | } 32 | } 33 | 34 | void FreeObject(size_t x) { 35 | next[x] = free; 36 | free = x; 37 | } 38 | 39 | void Compactify() { 40 | size_t index = 0; 41 | auto curr = head; 42 | while (next[curr] != -1) { 43 | auto dst = index; 44 | std::swap(next[prev[curr]], next[prev[dst]]); 45 | std::swap(prev[curr], prev[dst]); 46 | std::swap(prev[next[curr]], prev[next[dst]]); 47 | std::swap(next[curr], next[dst]); 48 | if (head == index) { 49 | head = curr; 50 | } 51 | curr = next[curr]; 52 | index++; 53 | } 54 | } 55 | }; 56 | 57 | 58 | int main() { 59 | 60 | } -------------------------------------------------------------------------------- /22/22.1-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | class GraphList { 7 | std::vector> adj; 8 | public: 9 | GraphList() : adj(n) {} 10 | 11 | [[nodiscard]] GraphList square() const { 12 | GraphList transposed; 13 | 14 | for (std::size_t i = 0; i < n; i++) { 15 | for (auto neighbor : adj[i]) { 16 | transposed.adj[neighbor].push_back(i); 17 | } 18 | } 19 | 20 | GraphList squared; 21 | 22 | for (std::size_t i = 0; i < n; i++) { 23 | for (auto neighbor : adj[i]) { 24 | squared.adj[i].push_back(neighbor); 25 | for (auto immediate : transposed.adj[neighbor]) { 26 | squared.adj[i].push_back(immediate); 27 | } 28 | } 29 | } 30 | 31 | return squared; 32 | } 33 | }; 34 | 35 | template 36 | class GraphMatrix { 37 | std::array adj; 38 | public: 39 | [[nodiscard]] GraphMatrix square() const { 40 | GraphMatrix squared; 41 | for (std::size_t i = 0; i < n; i++) { 42 | for (std::size_t j = 0; j < n; j++) { 43 | for (std::size_t k = 0; k < n; k++) { 44 | squared.adj[i * n + j] += adj[i * n + k] * adj[k * n + j]; 45 | } 46 | } 47 | } 48 | return squared; 49 | } 50 | }; 51 | 52 | 53 | 54 | int main() { 55 | 56 | } 57 | -------------------------------------------------------------------------------- /16/16.1_an_activity_selection_problem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace sr = std::ranges; 8 | 9 | std::vector> RecursiveActivitySelectorHelper(std::vector>& intervals, size_t k) { 10 | size_t m = k + 1; 11 | while (m < intervals.size() && intervals[m].first < intervals[k].second) { 12 | m++; 13 | } 14 | if (m < intervals.size()) { 15 | auto A = RecursiveActivitySelectorHelper(intervals, m); 16 | A.push_back(intervals[m]); 17 | return A; 18 | } else { 19 | return std::vector>(); 20 | } 21 | } 22 | 23 | std::vector> RecursiveActivitySelector(std::vector>& intervals) { 24 | sr::sort(intervals, [](auto& a, auto& b) {return a.second < b.second;}); 25 | auto A = RecursiveActivitySelectorHelper(intervals, 0); 26 | return A; 27 | } 28 | 29 | std::vector> GreedyActivitySelector(std::vector>& intervals) { 30 | sr::sort(intervals, [](auto& a, auto& b) {return a.second < b.second;}); 31 | size_t n = intervals.size(); 32 | std::vector> A; 33 | A.push_back(intervals[0]); 34 | size_t k = 0; 35 | for (size_t m = 1; m < n; m++) { 36 | if (intervals[m].first >= intervals[k].second) { 37 | A.push_back(intervals[m]); 38 | k = m; 39 | } 40 | } 41 | return A; 42 | } 43 | 44 | int main() { 45 | } 46 | -------------------------------------------------------------------------------- /32/32.1-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::vector DistinctNaiveMatcher(const std::string& T, const std::string& P) { 9 | assert(!T.empty() && !P.empty()); 10 | const std::size_t n = T.length(); 11 | const std::size_t m = P.length(); 12 | std::vector res; 13 | if (n < m) { 14 | return res; 15 | } 16 | std::size_t k = 0; 17 | for (std::size_t s = 0; s < n; s++) { 18 | if (T[s] == P[k]) { 19 | k++; 20 | } else if (T[s] == P[0]) { 21 | k = 1; 22 | } else { 23 | k = 0; 24 | } 25 | if (k == m) { 26 | res.push_back(s + 1 - m); 27 | k = 0; 28 | } 29 | } 30 | return res; 31 | } 32 | 33 | int main() { 34 | auto res = DistinctNaiveMatcher("acaabc", "abcd"); 35 | for (auto shift : res) { 36 | std::cout << shift << ' '; 37 | } 38 | std::cout << '\n'; 39 | auto res2 = DistinctNaiveMatcher("acaabc", "ac"); 40 | for (auto shift : res2) { 41 | std::cout << shift << ' '; 42 | } 43 | std::cout << '\n'; 44 | auto res3 = DistinctNaiveMatcher("acaabc", "ab"); 45 | for (auto shift : res3) { 46 | std::cout << shift << ' '; 47 | } 48 | std::cout << '\n'; 49 | auto res4 = DistinctNaiveMatcher("acaabc", "a"); 50 | for (auto shift : res4) { 51 | std::cout << shift << ' '; 52 | } 53 | std::cout << '\n'; 54 | } -------------------------------------------------------------------------------- /31/31.1-13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | constexpr std::array table = {1ull << (1ull << 0ull), 12 | 1ull << (1ull << 1ull), 13 | 1ull << (1ull << 2ull), 14 | 1ull << (1ull << 3ull), 15 | 1ull << (1ull << 4ull), 16 | 1ull << (1ull << 5ull)}; 17 | 18 | uint64_t toDecimal(std::vector& bits) { 19 | assert(!bits.empty()); 20 | if (bits.size() == 1) { 21 | return bits[0]; 22 | } 23 | if (!std::has_single_bit(bits.size())) { 24 | bits.resize(std::bit_ceil(bits.size())); 25 | } 26 | std::size_t n = bits.size(); 27 | std::vector lower_half (bits.begin(), bits.begin() + n / 2); 28 | std::vector upper_half (bits.begin() + n / 2, bits.end()); 29 | return toDecimal(upper_half) * table[std::floor(std::log2(n / 2))] + toDecimal(lower_half); 30 | } 31 | 32 | int main() { 33 | std::vector bits {false, true, true, false, 34 | true, true, false, true, 35 | true, true, false, false, 36 | true, false, true}; 37 | auto n = toDecimal(bits); 38 | std::cout << n << '\n'; 39 | std::bitset<16> bit_str (n); 40 | std::cout << bit_str << '\n'; 41 | 42 | 43 | } -------------------------------------------------------------------------------- /32/32.4-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::vector ComputePrefixFunction(const std::string& P) { 8 | assert(!P.empty()); 9 | const std::size_t m = P.length(); 10 | std::vector pi(m + 1); 11 | std::size_t k = 0; 12 | for (std::size_t q = 2; q <= m; q++) { 13 | while (k && P[k] != P[q - 1]) { 14 | k = pi[k]; 15 | } 16 | if (P[k] == P[q - 1]) { 17 | k++; 18 | } 19 | pi[q] = k; 20 | } 21 | return pi; 22 | } 23 | 24 | std::vector KMPMatcher(const std::string& T, const std::string& P) { 25 | const std::size_t n = T.length(); 26 | const std::size_t m = P.length(); 27 | std::vector res; 28 | if (n < m) { 29 | return res; 30 | } 31 | auto pi = ComputePrefixFunction(P); 32 | std::size_t q = 0; 33 | for (std::size_t i = 0; i < n; i++) { 34 | while (q && P[q] != T[i]) { 35 | q = pi[q]; 36 | } 37 | if (P[q] == T[i]) { 38 | q++; 39 | } 40 | if (q == m) { 41 | res.push_back((i + 1) - m); 42 | q = pi[q]; 43 | } 44 | } 45 | return res; 46 | } 47 | 48 | bool isCyclic(const std::string& T, const std::string& T2) { 49 | if (T.length() != T2.length()) { 50 | return false; 51 | } 52 | std::string TT = T + T; 53 | return !KMPMatcher(TT, T2).empty(); 54 | } 55 | 56 | int main() { 57 | assert(isCyclic("abc", "bca")); 58 | 59 | } -------------------------------------------------------------------------------- /10/10.2_linked_lists.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct ListNode { 8 | T key; 9 | ListNode* prev; 10 | std::unique_ptr> next; 11 | ListNode(const T& key) : key {key} {} 12 | }; 13 | 14 | template 15 | struct List { 16 | std::unique_ptr> head; 17 | }; 18 | 19 | template 20 | ListNode* ListSearch(const List& L, const T& k) { 21 | auto x = L.head.get(); 22 | while (x && x->key != k) { 23 | x = x->next.get(); 24 | } 25 | return x; 26 | } 27 | 28 | template 29 | void ListInsert(List& L, std::unique_ptr> x) { 30 | if (L.head) { 31 | L.head->prev = x.get(); 32 | } 33 | x->next = std::move(L.head); 34 | L.head = std::move(x); 35 | } 36 | 37 | template 38 | void ListDelete(List& L, ListNode* x) { 39 | if (x->prev) { 40 | x->prev->next = std::move(x->next); 41 | } else { 42 | L.head = std::move(x->next); 43 | } 44 | if (x->next) { 45 | x->next->prev = x->prev; 46 | } 47 | } 48 | 49 | int main() { 50 | auto x1 = std::make_unique>(1); 51 | auto x2 = std::make_unique>(2); 52 | auto x3 = std::make_unique>(3); 53 | List l; 54 | ListInsert(l, std::move(x1)); 55 | assert(ListSearch(l, 1)); 56 | ListInsert(l, std::move(x2)); 57 | ListInsert(l, std::move(x3)); 58 | ListDelete(l, ListSearch(l, 2)); 59 | assert(!ListSearch(l, 2)); 60 | 61 | } -------------------------------------------------------------------------------- /6/6.4_the_heapsort_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sr = std::ranges; 9 | 10 | size_t parent(size_t i) { 11 | return i / 2; 12 | } 13 | 14 | size_t left(size_t i) { 15 | return 2 * i + 1; 16 | } 17 | 18 | size_t right(size_t i) { 19 | return 2 * i + 2; 20 | } 21 | 22 | template 23 | void maxHeapify(std::pair&, size_t>& A, size_t i) { 24 | auto l = left(i); 25 | auto r = right(i); 26 | size_t largest = i; 27 | if (l < A.second && A.first[l] > A.first[i]) { 28 | largest = l; 29 | } 30 | if (r < A.second && A.first[r] > A.first[largest]) { 31 | largest = r; 32 | } 33 | if (largest != i) { 34 | std::swap(A.first[i], A.first[largest]); 35 | maxHeapify(A, largest); 36 | } 37 | } 38 | 39 | template 40 | void buildMaxHeap(std::pair&, size_t>& A) { 41 | A.second = A.first.size(); 42 | for (size_t i = A.first.size() / 2; i < A.first.size(); i--) { 43 | maxHeapify(A, i); 44 | } 45 | } 46 | 47 | template 48 | void heapSort(std::vector& v) { 49 | std::pair&, size_t> A = {v, 0}; 50 | buildMaxHeap(A); 51 | for (size_t i = A.first.size() - 1; i >= 1; i--) { 52 | std::swap(A.first[i], A.first[0]); 53 | A.second--; 54 | maxHeapify(A, 0); 55 | } 56 | } 57 | 58 | int main() { 59 | std::vector v {3, 1, 4, 1, 5, 9}; 60 | heapSort(v); 61 | assert(sr::is_sorted(v)); 62 | } -------------------------------------------------------------------------------- /22/22.2-9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Color { 8 | White, 9 | Gray, 10 | Black 11 | }; 12 | 13 | using info_t = std::tuple; 14 | 15 | template 16 | class Graph { 17 | std::vector> adj; 18 | public: 19 | Graph() : adj(n) { 20 | } 21 | 22 | std::vector infos; 23 | 24 | void DFSVisit(std::size_t u, std::size_t& time, std::vector& path) { 25 | time++; 26 | std::get<1>(infos[u]) = time; 27 | path.push_back(u); 28 | std::get<0>(infos[u]) = Color::Gray; 29 | for (auto v : adj[u]) { 30 | if (std::get<0>(infos[v]) == Color::White) { 31 | std::get<3>(infos[v]) = u; 32 | DFSVisit(v, time); 33 | } 34 | } 35 | std::get<0>(infos[u]) = Color::Black; 36 | time++; 37 | std::get<2>(infos[u]) = time; 38 | path.push_back(u); 39 | } 40 | 41 | void DFS() { 42 | infos = std::vector(n, std::make_tuple(Color::White, 0, 0, -1)); 43 | std::size_t time = 0; 44 | std::vector path; 45 | for (std::size_t i = 0; i < n; i++) { 46 | if (std::get<0>(infos[i]) == Color::White) { 47 | DFSVisit(i, time, path); 48 | } 49 | } 50 | for (auto vertex : path) { 51 | std::cout << vertex << ' '; 52 | } 53 | } 54 | }; 55 | 56 | 57 | int main() { 58 | 59 | } 60 | -------------------------------------------------------------------------------- /10/10.2-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct ListNode { 7 | T key; 8 | std::shared_ptr> next; 9 | std::weak_ptr> prev; 10 | ListNode(const T& key) : key {key} {} 11 | }; 12 | 13 | template 14 | struct List { 15 | private: 16 | std::shared_ptr> nil; 17 | public: 18 | List() { 19 | nil = std::make_shared>(T()); 20 | nil->next = nil; 21 | nil->prev = nil; 22 | } 23 | 24 | void ListDelete(std::shared_ptr>& x) { 25 | x->prev.lock()->next = x->next; 26 | x->next->prev = x->prev; 27 | x.reset(); 28 | } 29 | 30 | std::shared_ptr> ListSearch(const T& k) { 31 | auto x = nil->next; 32 | nil->key = k; 33 | while (x->key != k) { 34 | x = x->next; 35 | } 36 | if (x == nil) { 37 | return nullptr; 38 | } 39 | return x; 40 | } 41 | 42 | void ListInsert(std::shared_ptr>& x) { 43 | x->next = nil->next; 44 | nil->next->prev = x; 45 | nil->next = x; 46 | x->prev = nil; 47 | } 48 | }; 49 | 50 | int main() { 51 | auto p1 = std::make_shared>(1); 52 | auto p2 = std::make_shared>(2); 53 | auto p3 = std::make_shared>(3); 54 | List l; 55 | l.ListInsert(p1); 56 | assert(l.ListSearch(1)); 57 | l.ListInsert(p2); 58 | l.ListInsert(p3); 59 | l.ListDelete(p2); 60 | assert(!l.ListSearch(2)); 61 | 62 | } -------------------------------------------------------------------------------- /10/10.4-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct NaryTreeNode { 8 | T key; 9 | std::unique_ptr> left_child; 10 | std::unique_ptr> right_sibling; 11 | 12 | NaryTreeNode(const T& key) : key {key} {} 13 | }; 14 | 15 | template 16 | struct NaryTree { 17 | std::unique_ptr> root; 18 | }; 19 | 20 | template 21 | std::ostream& operator<<(std::ostream& os, NaryTreeNode* node) { 22 | if (node) { 23 | os << node->key << ' '; 24 | auto curr = node->left_child.get(); 25 | while (curr) { 26 | os << curr; 27 | curr = curr->right_sibling.get(); 28 | } 29 | } 30 | return os; 31 | } 32 | 33 | template 34 | std::ostream& operator<<(std::ostream& os, const NaryTree& tree) { 35 | os << tree.root.get(); 36 | return os; 37 | } 38 | 39 | int main() { 40 | NaryTree t; 41 | auto n1 = std::make_unique>(1); 42 | auto n2 = std::make_unique>(2); 43 | auto n3 = std::make_unique>(3); 44 | auto n4 = std::make_unique>(4); 45 | auto n5 = std::make_unique>(5); 46 | 47 | t.root = std::move(n1); 48 | t.root->left_child = std::move(n2); 49 | t.root->left_child->right_sibling = std::move(n3); 50 | t.root->left_child->right_sibling->right_sibling = std::move(n4); 51 | t.root->left_child->left_child = std::move(n5); 52 | 53 | std::cout << t; 54 | 55 | 56 | } -------------------------------------------------------------------------------- /17/17.1_aggregate_analysis_stack_operation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace crn = std::chrono; 8 | 9 | void Pop(std::stack& s) { 10 | if (!s.empty()) { 11 | s.pop(); 12 | } 13 | } 14 | 15 | void Push(std::stack& s) { 16 | s.push(1); 17 | } 18 | 19 | void Multipop(std::stack& s, std::size_t k) { 20 | while (!s.empty() && k) { 21 | s.pop(); 22 | k--; 23 | } 24 | } 25 | 26 | int main() { 27 | constexpr std::size_t SIZE = 1'000'000; 28 | 29 | std::stack s; 30 | auto t1 = crn::steady_clock::now(); 31 | for (std::size_t i = 0; i < SIZE / 2; i++) { 32 | Push(s); 33 | } 34 | for (std::size_t i = 0; i < SIZE / 2; i++) { 35 | Pop(s); 36 | } 37 | auto t2 = crn::steady_clock::now(); 38 | auto d1 = crn::duration_cast(t2 - t1); 39 | std::cout << d1.count() << "ms\n"; 40 | 41 | std::mt19937 gen(std::random_device{}()); 42 | std::uniform_int_distribution<> dist(1, 3); 43 | t1 = crn::steady_clock::now(); 44 | for (std::size_t i = 0; i < SIZE; i++) { 45 | switch (dist(gen)) { 46 | case 1: 47 | Push(s); 48 | break; 49 | case 2: 50 | Pop(s); 51 | break; 52 | case 3: 53 | Multipop(s, 20); 54 | break; 55 | } 56 | } 57 | t2 = crn::steady_clock::now(); 58 | d1 = crn::duration_cast(t2 - t1); 59 | std::cout << d1.count() << "ms\n"; 60 | 61 | } -------------------------------------------------------------------------------- /22/22.4-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Color { 8 | White, 9 | Gray, 10 | Black 11 | }; 12 | 13 | using info_t = std::tuple; 14 | 15 | template 16 | class Graph { 17 | std::vector> adj; 18 | public: 19 | Graph() : adj(n) { 20 | } 21 | 22 | std::vector infos; 23 | 24 | bool DFSVisit(std::size_t u, std::size_t& time) { 25 | time++; 26 | std::get<1>(infos[u]) = time; 27 | std::get<0>(infos[u]) = Color::Gray; 28 | for (auto v : adj[u]) { 29 | if (std::get<0>(infos[v]) == Color::White) { 30 | std::get<3>(infos[v]) = u; 31 | DFSVisit(v, time); 32 | } else if (std::get<0>(infos[v]) == Color::Gray) { 33 | return true; 34 | } 35 | } 36 | std::get<0>(infos[u]) = Color::Black; 37 | time++; 38 | std::get<2>(infos[u]) = time; 39 | return false; 40 | } 41 | 42 | bool hasCycle() { 43 | infos = std::vector(n, std::make_tuple(Color::White, 0, 0, -1)); 44 | std::size_t time = 0; 45 | for (std::size_t i = 0; i < n; i++) { 46 | if (std::get<0>(infos[i]) == Color::White) { 47 | auto res = DFSVisit(i, time); 48 | if (res) { 49 | return true; 50 | } 51 | } 52 | } 53 | return false; 54 | } 55 | }; 56 | 57 | 58 | int main() { 59 | 60 | } 61 | -------------------------------------------------------------------------------- /10/10.2_linked_lists_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct ListNode { 8 | T key; 9 | std::shared_ptr> next; 10 | std::weak_ptr> prev; 11 | ListNode(const T& key) : key {key} {} 12 | }; 13 | 14 | template 15 | struct List { 16 | private: 17 | std::shared_ptr> nil; 18 | public: 19 | List() { 20 | nil = std::make_shared>(T()); 21 | nil->next = nil; 22 | nil->prev = nil; 23 | } 24 | 25 | void ListDelete(std::shared_ptr>& x) { 26 | x->prev.lock()->next = x->next; 27 | x->next->prev = x->prev; 28 | x.reset(); 29 | } 30 | 31 | std::shared_ptr> ListSearch(const T& k) { 32 | auto x = nil->next; 33 | while (x != nil && x->key != k) { 34 | x = x->next; 35 | } 36 | if (x == nil) { 37 | return nullptr; 38 | } 39 | return x; 40 | } 41 | 42 | void ListInsert(std::shared_ptr>& x) { 43 | x->next = nil->next; 44 | nil->next->prev = x; 45 | nil->next = x; 46 | x->prev = nil; 47 | } 48 | }; 49 | 50 | int main() { 51 | auto p1 = std::make_shared>(1); 52 | auto p2 = std::make_shared>(2); 53 | auto p3 = std::make_shared>(3); 54 | List l; 55 | l.ListInsert(p1); 56 | assert(l.ListSearch(1)); 57 | l.ListInsert(p2); 58 | l.ListInsert(p3); 59 | l.ListDelete(p2); 60 | assert(!l.ListSearch(2)); 61 | 62 | } -------------------------------------------------------------------------------- /31/31.1-8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::strong_ordering isKthPowerEqualTo(std::size_t a, std::size_t k, std::size_t n) { 9 | std::size_t d = 1; 10 | auto bits = static_cast(std::ceil(std::log2(k))); 11 | std::bitset<64> K(k); 12 | for (std::size_t i = bits; i <= bits; i--) { 13 | d *= d; 14 | if (d > n) { 15 | return std::strong_ordering::greater; 16 | } 17 | if (K[i] == 1) { 18 | d *= a; 19 | if (d > n) { 20 | return std::strong_ordering::greater; 21 | } 22 | } 23 | } 24 | return d <=> n; 25 | } 26 | 27 | bool isKthPower(std::size_t n, std::size_t k) { 28 | assert(n > 1 && k > 1); 29 | std::size_t l = 2; 30 | std::size_t r = n / 2; 31 | while (l <= r) { 32 | std::size_t m = (l + r) / 2; 33 | auto res = isKthPowerEqualTo(m, k, n); 34 | if (res == std::strong_ordering::greater) { 35 | r = m - 1; 36 | } else if (res == std::strong_ordering::equal) { 37 | return true; 38 | } else { 39 | l = m + 1; 40 | } 41 | } 42 | return false; 43 | } 44 | 45 | bool isNontrivialPower(std::size_t n) { 46 | assert(n > 1); 47 | auto b = static_cast(std::ceil(std::log2(n))); 48 | for (std::size_t k = 2; k <= b; k++) { 49 | if (isKthPower(n, k)) { 50 | return true; 51 | } 52 | } 53 | return false; 54 | } 55 | 56 | int main() { 57 | assert(isNontrivialPower(19487171)); 58 | 59 | } -------------------------------------------------------------------------------- /35/35-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace sr = std::ranges; 12 | 13 | std::vector> GreedySchedule(std::size_t m, const std::vector& p) { 14 | assert(sr::all_of(p, [](auto num){return num > 0.0;})); 15 | std::priority_queue, std::vector>, std::greater<>> Q; 16 | const std::size_t n = p.size(); 17 | for (std::size_t i = 0; i < m; i++) { 18 | Q.emplace(0, i); 19 | } 20 | std::vector> A (m); 21 | for (std::size_t i = 0; i < n; i++) { 22 | auto [f_k, k] = Q.top(); 23 | Q.pop(); 24 | f_k += p[i]; 25 | A[k].push_back(i); 26 | Q.emplace(f_k, k); 27 | } 28 | return A; 29 | } 30 | 31 | int main() { 32 | constexpr std::size_t m = 5; 33 | constexpr std::size_t n = 100; 34 | std::vector p; 35 | 36 | std::mt19937 gen(std::random_device{}()); 37 | std::uniform_real_distribution<> dist(1.0, 100.0); 38 | p.reserve(n); 39 | for (std::size_t i = 0; i < n; i++) { 40 | p.push_back(dist(gen)); 41 | } 42 | 43 | for (auto p_val : p) { 44 | std::cout << p_val << ' '; 45 | } 46 | std::cout << '\n'; 47 | 48 | auto GS = GreedySchedule(m, p); 49 | for (const auto& gs : GS) { 50 | for (auto idx : gs) { 51 | std::cout << idx << ' '; 52 | } 53 | std::cout << '\n'; 54 | } 55 | std::cout << '\n'; 56 | 57 | } -------------------------------------------------------------------------------- /10/10.3-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct Stack { 9 | std::array data; 10 | size_t top = 0; 11 | }; 12 | 13 | template 14 | bool StackEmpty(const Stack& s) { 15 | return s.top == 0; 16 | } 17 | 18 | template 19 | void Push(Stack& s, const T& x) { 20 | s.data[s.top++] = x; 21 | } 22 | 23 | template 24 | T Pop(Stack& s) { 25 | if (StackEmpty(s)) { 26 | throw std::underflow_error("Stack underflow"); 27 | } else { 28 | return s.data[--s.second]; 29 | } 30 | } 31 | 32 | template 33 | struct GC { 34 | std::array prev; 35 | std::array next; 36 | std::array key = {0}; 37 | 38 | Stack free = 0; 39 | size_t head = 0; 40 | 41 | GC() { 42 | for (size_t i = 0; i < N; i++) { 43 | prev[i] = i - 1; 44 | next[i] = i + 1; 45 | } 46 | next[N - 1] = -1; 47 | } 48 | 49 | size_t AllocateObject() { 50 | if (StackEmpty(free)) { 51 | throw std::runtime_error("out of space"); 52 | } else { 53 | return Pop(free); 54 | } 55 | } 56 | 57 | void FreeObject(size_t x) { 58 | auto p = free.top + 1; 59 | next[prev[p]] = x; 60 | prev[next[p]] = x; 61 | key[x] = key[p]; 62 | prev[x] = prev[p]; 63 | next[x] = next[p]; 64 | Push(free, p); 65 | } 66 | }; 67 | 68 | 69 | int main() { 70 | 71 | } -------------------------------------------------------------------------------- /22/22.2-8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum class Color { 11 | White, 12 | Gray, 13 | Black 14 | }; 15 | 16 | using info_t = std::tuple; 17 | 18 | template 19 | class Graph { 20 | std::vector> adj; 21 | public: 22 | Graph() : adj(n) { 23 | infos = std::vector(n, std::make_tuple(Color::White, std::numeric_limits::max(), -1)); 24 | } 25 | 26 | std::vector infos; 27 | 28 | std::size_t BFS(std::size_t source) { 29 | assert(source < n); 30 | infos = std::vector(n, std::make_tuple(Color::White, std::numeric_limits::max(), -1)); 31 | infos[source] = {Color::Gray, 0, -1}; 32 | std::queue q; 33 | q.push(source); 34 | std::size_t last = -1; 35 | while (!q.empty()) { 36 | auto u = q.front(); 37 | q.pop(); 38 | for (auto v : adj[u]) { 39 | if (std::get<0>(infos[v]) == Color::White) { 40 | infos[v] = {Color::Gray, std::get<1>(infos[u]) + 1, u}; 41 | q.push(v); 42 | last = v; 43 | } 44 | } 45 | std::get<0>(infos[u]) = Color::Black; 46 | } 47 | return last; 48 | } 49 | 50 | std::size_t getDiameter() { 51 | auto u = BFS(0); 52 | auto v = BFS(u); 53 | return std::get<1>(infos[v]); 54 | } 55 | }; 56 | 57 | 58 | int main() { 59 | 60 | } 61 | -------------------------------------------------------------------------------- /7/7.4-6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | 11 | std::mt19937 gen(std::random_device{}()); 12 | 13 | template 14 | size_t partition(std::vector& A, size_t p, size_t r) { 15 | std::uniform_int_distribution<> dist(p, r); 16 | std::vector temp; 17 | temp.push_back(dist(gen)); 18 | temp.push_back(dist(gen)); 19 | temp.push_back(dist(gen)); 20 | sr::sort(temp); 21 | size_t idx = temp[1]; 22 | 23 | T x = A[idx]; 24 | size_t i = p; 25 | for (size_t j = p; j < r; j++) { 26 | if (A[j] >= x) { 27 | std::swap(A[i], A[j]); 28 | i++; 29 | } 30 | } 31 | std::swap(A[i], A[r]); 32 | return i; 33 | } 34 | 35 | int main() { 36 | constexpr double alpha = 0.3; 37 | constexpr size_t trials = 1'000; 38 | constexpr size_t N = 1'000; 39 | 40 | std::vector v (N); 41 | std::iota(v.begin(), v.end(), 0); 42 | 43 | size_t balanced_count = 0; 44 | for (size_t i = 0; i < trials; i++) { 45 | auto u = v; 46 | sr::shuffle(u, gen); 47 | size_t q = partition(u, 0, u.size() - 1); 48 | 49 | if (q < (1.0 - alpha) * N && q > (alpha) * N) { 50 | balanced_count++; 51 | } 52 | } 53 | 54 | std::cout << "Probability that the partition is balanced than (1-a)/a : " 55 | << static_cast(balanced_count) / static_cast(trials) << '\n'; 56 | std::cout << "1 - 12a^2 + 16a^3 : " << 1.0 - 12.0 * std::pow(alpha, 2) + 16.0 * std::pow(alpha, 3) << '\n'; 57 | 58 | } -------------------------------------------------------------------------------- /4/4-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::mt19937 gen(std::random_device{}()); 7 | std::bernoulli_distribution d(0.5); 8 | 9 | std::vector chips; 10 | 11 | std::pair report(size_t A, size_t B) { 12 | std::pair res = {false, false}; 13 | if (chips[A]) { 14 | res.first = chips[B]; 15 | } else { 16 | res.first = d(gen); 17 | } 18 | if (chips[B]) { 19 | res.second = chips[A]; 20 | } else { 21 | res.second = d(gen); 22 | } 23 | return res; 24 | } 25 | 26 | 27 | int main() { 28 | constexpr size_t NUM_CHIPS = 30; 29 | chips.resize(NUM_CHIPS); 30 | for (size_t i = 0; i < 1 + NUM_CHIPS / 2; i++) { 31 | chips[i] = 1; 32 | } 33 | std::shuffle(chips.begin(), chips.end(), gen); 34 | std::vector predictions(chips.size()); 35 | for (size_t i = 0; i < NUM_CHIPS - 1; i++) { 36 | auto [resA, resB] = report(i, i + 1); 37 | if (resA && resB) { // report say that both is good. 38 | predictions[i] = 1; // take the first, discard the second 39 | } else { 40 | i++; // discard both of them 41 | } 42 | } 43 | size_t last_good = 0; 44 | for (size_t i = NUM_CHIPS - 1; i < NUM_CHIPS; i--) { 45 | if (predictions[i]) { 46 | last_good = i; 47 | break; 48 | } 49 | } 50 | for (size_t i = 0; i < NUM_CHIPS; i++) { 51 | if (i == last_good) { 52 | continue; 53 | } 54 | bool resI = report(last_good, i).first; 55 | predictions[i] = resI; 56 | } 57 | assert(predictions == chips); 58 | 59 | } -------------------------------------------------------------------------------- /15/15-3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using Point = std::pair; 10 | 11 | double distance(const Point& p1, const Point& p2) { 12 | return std::hypot(p1.first - p2.first, p1.second - p2.second); 13 | } 14 | 15 | std::pair>, std::vector>> EuclideanTSP(std::vector& p) { 16 | std::sort(p.begin(), p.end()); 17 | size_t n = p.size(); 18 | std::vector> b (n, std::vector (n)); 19 | std::vector> r (n, std::vector (n)); 20 | b[0][1] = distance(p[0], p[1]); 21 | for (size_t j = 2; j < n; j++) { 22 | for (size_t i = 0; i < j - 1; i++) { 23 | b[i][j] = b[i][j - 1] + distance(p[j - 1], p[j]); 24 | r[i][j] = j - 1; 25 | } 26 | b[j - 1][j] = std::numeric_limits::max(); 27 | for (size_t k = 0; k < j - 1; k++) { 28 | auto q = b[k][j - 1] + distance(p[k], p[j]); 29 | if (q < b[j - 1][j]) { 30 | b[j - 1][j] = q; 31 | r[j - 1][j] = k; 32 | } 33 | } 34 | } 35 | b[n - 1][n - 1] = b[n - 2][n - 1] + distance(p[n - 2], p[n - 1]); 36 | return {b, r}; 37 | } 38 | 39 | int main() { 40 | std::vector p; 41 | p.emplace_back(0.0, 0.0); 42 | p.emplace_back(1.0, 6.0); 43 | p.emplace_back(2.0, 3.0); 44 | p.emplace_back(5.0, 2.0); 45 | p.emplace_back(6.0, 5.0); 46 | p.emplace_back(7.0, 1.0); 47 | p.emplace_back(8.0, 4.0); 48 | auto [b, r] = EuclideanTSP(p); 49 | std::cout << b.back().back(); 50 | 51 | } -------------------------------------------------------------------------------- /10/10.1-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct Queue { 9 | std::vector data; 10 | size_t head = 0; 11 | size_t tail = 0; 12 | }; 13 | 14 | template 15 | void HeadEnqueue(Queue& q, const T& x) { 16 | if (q.head == q.tail + 1 || (q.head == 0 && q.tail == q.data.size() - 1)) { 17 | throw std::overflow_error("Queue overflow"); 18 | } 19 | q.data[q.head] = x; 20 | if (q.head == 0) { 21 | q.head = q.data.size() - 1; 22 | } else { 23 | q.head--; 24 | } 25 | } 26 | 27 | template 28 | void TailEnqueue(Queue& q, const T& x) { 29 | if (q.head == q.tail + 1 || (q.head == 0 && q.tail == q.data.size() - 1)) { 30 | throw std::overflow_error("Queue overflow"); 31 | } 32 | q.data[q.tail] = x; 33 | if (q.tail == q.data.size() - 1) { 34 | q.tail = 0; 35 | } else { 36 | q.tail++; 37 | } 38 | } 39 | 40 | template 41 | void HeadDequeue(Queue& q) { 42 | if (q.head == q.tail) { 43 | throw std::underflow_error("Queue underflow"); 44 | } 45 | T x = q.data[q.head]; 46 | if (q.head == q.data.size() - 1) { 47 | q.head = 0; 48 | } else { 49 | q.head++; 50 | } 51 | return x; 52 | } 53 | 54 | template 55 | void TailDequeue(Queue& q) { 56 | if (q.head == q.tail) { 57 | throw std::underflow_error("Queue underflow"); 58 | } 59 | T x = q.data[q.tail]; 60 | if (q.tail == 0) { 61 | q.tail = q.data.size() - 1; 62 | } else { 63 | q.tail--; 64 | } 65 | return x; 66 | } 67 | 68 | int main() { 69 | 70 | } -------------------------------------------------------------------------------- /22/22.3-7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | enum class Color { 9 | White, 10 | Gray, 11 | Black 12 | }; 13 | 14 | using info_t = std::tuple; 15 | 16 | template 17 | class Graph { 18 | std::vector> adj; 19 | public: 20 | Graph() : adj(n) { 21 | } 22 | 23 | std::vector infos; 24 | 25 | void DFSIterative() { 26 | infos = std::vector(n, std::make_tuple(Color::White, 0, 0, -1)); 27 | std::size_t time = 0; 28 | std::stack S; 29 | for (std::size_t u = 0; u < n; u++) { 30 | if (std::get<0>(infos[u]) == Color::White) { 31 | S.push(u); 32 | while (!S.empty()) { 33 | auto v = S.top(); 34 | time++; 35 | std::get<0>(infos[v]) = Color::Gray; 36 | std::get<1>(infos[v]) = time; 37 | bool finished = true; 38 | for (auto w : adj[v]) { 39 | if (std::get<0>(infos[w]) == Color::White) { 40 | S.push(w); 41 | finished = false; 42 | } 43 | } 44 | if (finished) { 45 | S.pop(); 46 | time++; 47 | std::get<0>(infos[v]) = Color::Black; 48 | std::get<2>(infos[v]) = time; 49 | } 50 | } 51 | } 52 | } 53 | } 54 | }; 55 | 56 | 57 | int main() { 58 | 59 | } 60 | -------------------------------------------------------------------------------- /8/8-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | 11 | std::mt19937 gen(std::random_device{}()); 12 | 13 | std::vector> jugs; 14 | 15 | void matchJugs(std::vector& R, std::vector& B) { 16 | assert(R.size() == B.size()); 17 | if (R.empty()) { 18 | return; 19 | } else if (R.size() == 1) { 20 | jugs.emplace_back(R[0], B[0]); 21 | } else { 22 | std::uniform_int_distribution<> dist(0, R.size() - 1); 23 | int r = R[dist(gen)]; 24 | std::vector B_s, B_l, R_s, R_l; 25 | for (auto& b : B) { 26 | if (b == r) { 27 | jugs.emplace_back(r, b); 28 | } else if (b > r) { 29 | B_l.push_back(b); 30 | } else { 31 | B_s.push_back(b); 32 | } 33 | } 34 | auto b = jugs.back().second; 35 | for (auto t : R) { 36 | if (t == b) { 37 | continue; 38 | } else if (t > b) { 39 | R_l.push_back(t); 40 | } else { 41 | R_s.push_back(t); 42 | } 43 | } 44 | R.clear(); 45 | B.clear(); 46 | matchJugs(R_l, B_l); 47 | matchJugs(R_s, B_s); 48 | } 49 | } 50 | 51 | int main() { 52 | constexpr size_t N = 1'000; 53 | 54 | std::vector R (N), B (N); 55 | std::iota(R.begin(), R.end(), 0); 56 | std::iota(B.begin(), B.end(), 0); 57 | sr::shuffle(R, gen); 58 | sr::shuffle(B, gen); 59 | matchJugs(R, B); 60 | assert(sr::all_of(jugs, [](auto& p) {return p.first == p.second;})); 61 | 62 | } -------------------------------------------------------------------------------- /9/9-1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sr = std::ranges; 10 | namespace srv = std::ranges::views; 11 | 12 | template 13 | std::vector largestIthSorted1(const std::vector& A, size_t i) { 14 | auto B = A; 15 | sr::sort(B); 16 | std::vector C (std::make_move_iterator(B.begin() + B.size() - i), std::make_move_iterator(B.end())); 17 | return C; 18 | } 19 | 20 | template 21 | std::vector largestIthSorted2(const std::vector& A, size_t i) { 22 | std::priority_queue q (A.begin(), A.end()); 23 | std::vector C; 24 | for (size_t j = 0; j < i; j++) { 25 | C.push_back(q.top()); 26 | q.pop(); 27 | } 28 | sr::reverse(C); 29 | return C; 30 | } 31 | 32 | template 33 | std::vector largestIthSorted3(const std::vector& A, size_t i) { 34 | auto B = A; 35 | sr::nth_element(B, B.begin() + B.size() - i); 36 | sr::sort(B | srv::drop(B.size() - i)); 37 | std::vector C (std::make_move_iterator(B.begin() + B.size() - i), std::make_move_iterator(B.end())); 38 | return C; 39 | } 40 | 41 | int main() { 42 | std::vector v {3, 1, 6, 2, 5, 4, 7, 9, 8}; 43 | size_t i = 4; 44 | auto a1 = largestIthSorted1(v, i); 45 | for (auto n : a1) { 46 | std::cout << n << ' '; 47 | } 48 | std::cout << '\n'; 49 | auto a2 = largestIthSorted2(v, i); 50 | for (auto n : a2) { 51 | std::cout << n << ' '; 52 | } 53 | std::cout << '\n'; 54 | auto a3 = largestIthSorted3(v, i); 55 | for (auto n : a3) { 56 | std::cout << n << ' '; 57 | } 58 | std::cout << '\n'; 59 | 60 | 61 | } -------------------------------------------------------------------------------- /22/22.2_breadth_first_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | class Graph { 12 | std::vector> adj; 13 | public: 14 | Graph() : adj(n) {} 15 | 16 | enum class Color { 17 | White, 18 | Gray, 19 | Black 20 | }; 21 | 22 | using info_t = std::tuple; 23 | 24 | std::vector BFS(std::size_t source) { 25 | assert(source < n); 26 | std::vector infos (n, std::make_tuple(Color::White, std::numeric_limits::max(), -1)); 27 | infos[source] = {Color::Gray, 0, -1}; 28 | std::queue q; 29 | q.push(source); 30 | while (!q.empty()) { 31 | auto u = q.front(); 32 | q.pop(); 33 | for (auto v : adj[u]) { 34 | if (std::get<0>(infos[v]) == Color::White) { 35 | infos[v] = {Color::Gray, std::get<1>(infos[u]) + 1, u}; 36 | q.push(v); 37 | } 38 | } 39 | std::get<0>(infos[u]) = Color::Black; 40 | } 41 | return infos; 42 | } 43 | 44 | void printPath(std::size_t source, std::size_t dest, const std::vector& infos) { 45 | if (dest == source) { 46 | std::cout << source; 47 | } else if (std::get<2>(infos[dest]) == -1) { 48 | std::cout << "No path from " << source << " to " << dest << " exists\n"; 49 | } else { 50 | printPath(source, std::get<2>(infos[dest]), infos); 51 | } 52 | } 53 | 54 | }; 55 | 56 | int main() { 57 | 58 | } 59 | -------------------------------------------------------------------------------- /30/30.2_the_DFT_and_FFT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace se = std::execution; 16 | namespace sr = std::ranges; 17 | namespace sn = std::numbers; 18 | 19 | std::vector> RecursiveFFT(std::vector& A) { 20 | using namespace std::complex_literals; 21 | std::size_t n = A.size(); 22 | if (n == 1) { 23 | return std::vector> {A[0]}; 24 | } 25 | auto w_n = std::exp(2.0i * sn::pi / static_cast(n)); 26 | std::complex w = 1; 27 | std::vector A0 (n / 2); 28 | std::vector A1 (n / 2); 29 | for (std::size_t i = 0; i < n; i += 2) { 30 | A0[i / 2] = A[i]; 31 | A1[i / 2] = A[i + 1]; 32 | } 33 | auto y0 = RecursiveFFT(A0); 34 | auto y1 = RecursiveFFT(A1); 35 | std::vector> y (n); 36 | for (std::size_t k = 0; k < n / 2; k++) { 37 | y[k] = y0[k] + w * y1[k]; 38 | y[k + n / 2] = y0[k] - w * y1[k]; 39 | w *= w_n; 40 | } 41 | return y; 42 | } 43 | 44 | int main() { 45 | constexpr std::size_t N = 1u << 5u; 46 | 47 | std::vector v (N); 48 | std::iota(v.begin(), v.end(), 0); 49 | std::mt19937 gen(std::random_device{}()); 50 | sr::shuffle(v, gen); 51 | 52 | for (const auto& n : v) { 53 | std::cout << n << ' '; 54 | } 55 | std::cout << '\n'; 56 | 57 | auto W = RecursiveFFT(v); 58 | for (const auto& w : W) { 59 | std::cout << w << ' '; 60 | } 61 | std::cout << '\n'; 62 | 63 | } -------------------------------------------------------------------------------- /30/30.1-5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::pair, double> LongDivision(const std::vector& A, double x_0) { 8 | assert(!A.empty()); 9 | auto A_ = A; 10 | std::size_t n = A.size(); 11 | std::vector q (n - 1); 12 | for (std::size_t k = n - 2; k < n; k--) { 13 | q[k] = A_[k + 1]; 14 | A_[k] += x_0 * A_[k + 1]; 15 | } 16 | auto r = A_[0]; 17 | return {q, r}; 18 | } 19 | 20 | std::vector LagrangeFormula(const std::vector>& points) { 21 | assert(!points.empty()); 22 | std::size_t n = points.size(); 23 | std::vector A(n + 1); 24 | A[0] = -points[0].first; 25 | A[1] = 1; 26 | for (std::size_t k = 1; k < n; k++) { 27 | for (std::size_t j = k; j <= k; j--) { 28 | A[j + 1] += A[j]; 29 | A[j] *= -points[k].first; 30 | } 31 | } 32 | std::vector A_(n); 33 | for (std::size_t k = 0; k < n; k++) { 34 | auto [A_k, _] = LongDivision(A, points[k].first); 35 | double p = 1; 36 | for (std::size_t j = 0; j < n; j++) { 37 | if (j == k) { 38 | continue; 39 | } 40 | p *= (points[k].first - points[j].first); 41 | } 42 | for (std::size_t j = 0; j < n; j++) { 43 | A_k[j] *= points[k].second / p; 44 | } 45 | for (std::size_t j = 0; j < n; j++) { 46 | A_[j] += A_k[j]; 47 | } 48 | } 49 | return A_; 50 | } 51 | 52 | int main() { 53 | std::vector> points {{0, 0}, {1, 1}, {2, 4}}; 54 | auto A = LagrangeFormula(points); 55 | for (auto a_n : A) { 56 | std::cout << a_n << ' '; 57 | } 58 | std::cout << '\n'; 59 | 60 | } -------------------------------------------------------------------------------- /35/35.4-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sr = std::ranges; 11 | 12 | std::mt19937 gen(std::random_device{}()); 13 | std::bernoulli_distribution to_add(0.5); 14 | 15 | std::size_t CountSatisfiedClauses(const std::vector>& clauses, std::size_t num_variables) { 16 | std::unordered_set satisfied; 17 | for (std::size_t i = 0; i < num_variables; i++) { 18 | if (to_add(gen)) { 19 | satisfied.insert(i); 20 | } 21 | } 22 | std::size_t cnt = 0; 23 | for (const auto& clause : clauses) { 24 | for (auto var : satisfied) { 25 | if (clause.contains(var)) { 26 | cnt++; 27 | break; 28 | } 29 | } 30 | } 31 | return cnt; 32 | } 33 | 34 | int main() { 35 | constexpr std::size_t num_clauses = 100; 36 | constexpr std::size_t num_variables = 100; 37 | std::vector vars (num_variables); 38 | std::iota(vars.begin(), vars.end(), 0); 39 | std::vector> clauses; 40 | 41 | for (std::size_t i = 0; i < num_clauses; i++) { 42 | sr::shuffle(vars, gen); 43 | std::unordered_set clause; 44 | clause.insert(vars[0]); 45 | clause.insert(vars[1]); 46 | clause.insert(vars[2]); 47 | std::size_t j = 3; 48 | while (to_add(gen) && j < num_variables) { 49 | clause.insert(vars[j]); 50 | j++; 51 | } 52 | clauses.push_back(std::move(clause)); 53 | } 54 | 55 | auto count_clauses = CountSatisfiedClauses(clauses, num_variables); 56 | std::cout << count_clauses << " / " << num_clauses << '\n'; 57 | } -------------------------------------------------------------------------------- /22/22.3-10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Color { 8 | White, 9 | Gray, 10 | Black 11 | }; 12 | 13 | using info_t = std::tuple; 14 | 15 | template 16 | class Graph { 17 | std::vector> adj; 18 | public: 19 | Graph() : adj(n) { 20 | } 21 | 22 | std::vector infos; 23 | 24 | void DFSVisit(std::size_t u, std::size_t& time) { 25 | time++; 26 | std::get<1>(infos[u]) = time; 27 | std::get<0>(infos[u]) = Color::Gray; 28 | for (auto v : adj[u]) { 29 | if (std::get<0>(infos[v]) == Color::White) { 30 | std::cout << '(' << u << ", " << v << ") is a tree edge\n"; 31 | std::get<3>(infos[v]) = u; 32 | DFSVisit(v, time); 33 | } else if (std::get<0>(infos[v]) == Color::Gray) { 34 | std::cout << '(' << u << ", " << v << ") is a back edge\n"; 35 | } else if (std::get<1>(infos[v]) > std::get<1>(infos[u])) { 36 | std::cout << '(' << u << ", " << v << ") is a forward edge\n"; 37 | } else { 38 | std::cout << '(' << u << ", " << v << ") is a cross edge\n"; 39 | } 40 | } 41 | std::get<0>(infos[u]) = Color::Black; 42 | time++; 43 | std::get<2>(infos[u]) = time; 44 | } 45 | 46 | void DFS() { 47 | infos = std::vector(n, std::make_tuple(Color::White, 0, 0, -1)); 48 | std::size_t time = 0; 49 | for (std::size_t i = 0; i < n; i++) { 50 | if (std::get<0>(infos[i]) == Color::White) { 51 | DFSVisit(i, time); 52 | } 53 | } 54 | } 55 | }; 56 | 57 | 58 | int main() { 59 | 60 | } 61 | -------------------------------------------------------------------------------- /22/22.3-13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | enum class Color { 9 | White, 10 | Gray, 11 | Black 12 | }; 13 | 14 | using info_t = std::tuple; 15 | 16 | template 17 | class Graph { 18 | std::vector> adj; 19 | public: 20 | Graph() : adj(n) { 21 | } 22 | 23 | std::vector infos; 24 | 25 | bool isSinglyConnected() { 26 | infos = std::vector(n, std::make_tuple(Color::White, 0, 0, -1)); 27 | std::size_t time = 0; 28 | std::stack S; 29 | for (std::size_t u = 0; u < n; u++) { 30 | if (std::get<0>(infos[u]) == Color::White) { 31 | S.push(u); 32 | while (!S.empty()) { 33 | auto v = S.top(); 34 | time++; 35 | std::get<0>(infos[v]) = Color::Gray; 36 | std::get<1>(infos[v]) = time; 37 | bool finished = true; 38 | for (auto w : adj[v]) { 39 | if (std::get<0>(infos[w]) == Color::White) { 40 | S.push(w); 41 | finished = false; 42 | } else { 43 | return false; 44 | } 45 | } 46 | if (finished) { 47 | S.pop(); 48 | time++; 49 | std::get<0>(infos[v]) = Color::Black; 50 | std::get<2>(infos[v]) = time; 51 | } 52 | } 53 | } 54 | } 55 | return true; 56 | } 57 | }; 58 | 59 | 60 | int main() { 61 | 62 | } 63 | -------------------------------------------------------------------------------- /15/15.4-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Dir { 8 | upleft, 9 | up, 10 | left, 11 | }; 12 | 13 | template 14 | std::pair>, std::vector>> 15 | LCSLength(const std::vector& X, const std::vector& Y) { 16 | std::vector> B (X.size(), std::vector(Y.size(), Dir::upleft)); 17 | std::vector> C (X.size() + 1, std::vector(Y.size() + 1)); 18 | for (size_t i = 0; i < X.size(); i++) { 19 | for (size_t j = 0; j < Y.size(); j++) { 20 | if (X[i] == Y[j]) { 21 | C[i + 1][j + 1] = C[i][j] + 1; 22 | B[i][j] = Dir::upleft; 23 | } else if (C[i][j + 1] >= C[i + 1][j]) { 24 | C[i + 1][j + 1] = C[i][j + 1]; 25 | B[i][j] = Dir::up; 26 | } else { 27 | C[i + 1][j + 1] = C[i + 1][j]; 28 | B[i][j] = Dir::left; 29 | } 30 | } 31 | } 32 | return {C, B}; 33 | } 34 | 35 | template 36 | void PrintLCS(const std::vector>& C, const std::vector& X, const std::vector& Y, size_t i, size_t j) { 37 | if (C[i + 1][j + 1] == 0) { 38 | return; 39 | } 40 | if (X[i] == Y[j]) { 41 | PrintLCS(C, X, Y, i - 1, j - 1); 42 | std::cout << X[i]; 43 | } else if (C[i][j + 1] > C[i + 1][j]) { 44 | PrintLCS(C, X, Y, i - 1, j); 45 | } else { 46 | PrintLCS(C, X, Y, i, j - 1); 47 | } 48 | } 49 | 50 | int main() { 51 | std::vector X = {'A', 'B', 'C', 'B', 'D', 'A', 'B'}; 52 | std::vector Y = {'B', 'D', 'C', 'A', 'B', 'A'}; 53 | auto [C, B] = LCSLength(X, Y); 54 | PrintLCS(C, X, Y, X.size() - 1, Y.size() - 1); 55 | 56 | 57 | } -------------------------------------------------------------------------------- /8/8.4-4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template > 11 | void insertionSort(std::vector& A, Comp comp = Comp()) { 12 | for (size_t j = 1; j < A.size(); j++) { 13 | T key = A[j]; 14 | size_t i = j - 1; 15 | while (i < A.size() && comp(A[i], key)) { 16 | A[i + 1] = A[i]; 17 | i--; 18 | } 19 | A[i + 1] = key; 20 | } 21 | } 22 | 23 | void bucketSort(std::vector>& A) { 24 | std::vector>> B (A.size()); 25 | for (const auto& [x, y] : A) { 26 | auto r = std::hypot(x, y); 27 | B[std::floor(std::pow(r, 2.0) * A.size())].emplace_back(x, y); 28 | } 29 | for (auto& v : B) { 30 | insertionSort(v, 31 | [](auto &a, auto &b) { return std::hypot(a.first, a.second) > std::hypot(b.first, b.second); }); 32 | } 33 | A.clear(); 34 | for (auto& v : B) { 35 | A.insert(A.end(), std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())); 36 | } 37 | } 38 | 39 | int main() { 40 | std::mt19937 gen(std::random_device{}()); 41 | std::uniform_real_distribution<> radius(0.0, 1.0); 42 | std::uniform_real_distribution<> angle(0.0, 2 * M_PI); 43 | constexpr size_t N = 100; 44 | std::vector> A; 45 | 46 | for (size_t i = 0; i < N; i++) { 47 | auto r = radius(gen); 48 | auto t = angle(gen); 49 | A.emplace_back(r * std::cos(t), r * std::sin(t)); 50 | } 51 | 52 | bucketSort(A); 53 | 54 | for (const auto& [x, y] : A) { 55 | std::cout << "(" << x << ", " << y << ") : r = " << std::hypot(x, y) << '\n'; 56 | } 57 | 58 | 59 | 60 | } -------------------------------------------------------------------------------- /8/8.3_radix_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace sr = std::ranges; 11 | 12 | std::mt19937 gen(std::random_device{}()); 13 | 14 | void radixSort(std::vector& A, size_t d) { 15 | assert(*sr::max_element(A) < std::pow(10u, d)); 16 | for (size_t i = 0; i < d; i++) { 17 | auto comp = [&i](size_t a, size_t b) { 18 | return ((a / static_cast(std::pow(10u, i))) % 10) < 19 | ((b / static_cast(std::pow(10u, i))) % 10); 20 | }; 21 | sr::stable_sort(A, comp); 22 | } 23 | } 24 | 25 | int main() { 26 | constexpr size_t N = 50'000; 27 | std::vector A (N); 28 | std::uniform_int_distribution<> dist(0, 99); 29 | for (auto& n : A) { 30 | n = dist(gen); 31 | } 32 | constexpr size_t TRIALS = 1'000; 33 | crn::milliseconds DT1 (0), DT2(0); 34 | for (size_t t = 0; t < TRIALS; t++) { 35 | sr::shuffle(A, gen); 36 | auto t1 = crn::steady_clock::now(); 37 | sr::sort(A); 38 | auto t2 = crn::steady_clock::now(); 39 | auto dt1 = crn::duration_cast(t2 - t1); 40 | DT1 += dt1; 41 | assert(sr::is_sorted(A)); 42 | sr::shuffle(A, gen); 43 | auto t3 = crn::steady_clock::now(); 44 | radixSort(A, 2); 45 | auto t4 = crn::steady_clock::now(); 46 | auto dt2 = crn::duration_cast(t4 - t3); 47 | DT2 += dt2; 48 | assert(sr::is_sorted(A)); 49 | } 50 | 51 | std::cout << "Sorting " << N << " elements in range of [0, 99] using std::sort : " << DT1.count() / TRIALS << "ms\n"; 52 | std::cout << "Sorting " << N << " elements in range of [0, 99] using radix sort : " << DT2.count() / TRIALS << "ms\n"; 53 | 54 | 55 | } -------------------------------------------------------------------------------- /15/15.4_longest_common_subsequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | enum class Dir { 8 | upleft, 9 | up, 10 | left, 11 | }; 12 | 13 | template 14 | std::pair>, std::vector>> 15 | LCSLength(const std::vector& X, const std::vector& Y) { 16 | std::vector> B (X.size(), std::vector(Y.size(), Dir::upleft)); 17 | std::vector> C (X.size() + 1, std::vector(Y.size() + 1)); 18 | for (size_t i = 0; i < X.size(); i++) { 19 | for (size_t j = 0; j < Y.size(); j++) { 20 | if (X[i] == Y[j]) { 21 | C[i + 1][j + 1] = C[i][j] + 1; 22 | B[i][j] = Dir::upleft; 23 | } else if (C[i][j + 1] >= C[i + 1][j]) { 24 | C[i + 1][j + 1] = C[i][j + 1]; 25 | B[i][j] = Dir::up; 26 | } else { 27 | C[i + 1][j + 1] = C[i + 1][j]; 28 | B[i][j] = Dir::left; 29 | } 30 | } 31 | } 32 | return {C, B}; 33 | } 34 | 35 | template 36 | void PrintLCS(const std::vector>& B, const std::vector& X, const std::vector& Y, size_t i, size_t j) { 37 | if (i >= X.size() || j >= Y.size()) { 38 | return; 39 | } 40 | if (B[i][j] == Dir::upleft) { 41 | PrintLCS(B, X, Y, i - 1, j - 1); 42 | std::cout << X[i]; 43 | } else if (B[i][j] == Dir::up) { 44 | PrintLCS(B, X, Y, i - 1, j); 45 | } else { 46 | PrintLCS(B, X, Y, i, j - 1); 47 | } 48 | } 49 | 50 | int main() { 51 | std::vector X = {'A', 'B', 'C', 'B', 'D', 'A', 'B'}; 52 | std::vector Y = {'B', 'D', 'C', 'A', 'B', 'A'}; 53 | auto [C, B] = LCSLength(X, Y); 54 | PrintLCS(B, X, Y, X.size() - 1, Y.size() - 1); 55 | 56 | 57 | } -------------------------------------------------------------------------------- /12/12-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct Node { 8 | bool hasValue = false; 9 | std::string value; 10 | std::unique_ptr left; 11 | std::unique_ptr right; 12 | 13 | Node() = default; 14 | Node(std::string value) : value {std::move(value)} {}; 15 | }; 16 | 17 | struct RadixTree { 18 | std::unique_ptr root; 19 | 20 | RadixTree () { 21 | root = std::make_unique(); 22 | } 23 | 24 | void Insert(const std::string& value) { 25 | auto node = root.get(); 26 | for (char c : value) { 27 | if (c == '0') { 28 | if (!node->left) { 29 | node->left = std::make_unique(); 30 | } 31 | node = node->left.get(); 32 | } else if (c == '1') { 33 | if (!node->right) { 34 | node->right = std::make_unique(); 35 | } 36 | node = node->right.get(); 37 | } else { 38 | throw std::invalid_argument("Not a bit string"); 39 | } 40 | } 41 | node->hasValue = true; 42 | node->value = value; 43 | } 44 | }; 45 | 46 | std::ostream& operator<<(std::ostream& os, Node* node) { 47 | if (node) { 48 | if (node->hasValue) { 49 | os << node->value << ' '; 50 | } 51 | os << node->left.get(); 52 | os << node->right.get(); 53 | } 54 | return os; 55 | } 56 | 57 | std::ostream& operator<<(std::ostream& os, const RadixTree& tree) { 58 | os << tree.root.get(); 59 | return os; 60 | } 61 | 62 | int main() { 63 | RadixTree tree; 64 | tree.Insert("0"); 65 | tree.Insert("10"); 66 | tree.Insert("011"); 67 | tree.Insert("100"); 68 | tree.Insert("1011"); 69 | std::cout << tree; 70 | } --------------------------------------------------------------------------------