├── .gitignore ├── README.md ├── week1_programming_challenges ├── 1_sum_of_two_digits │ └── APlusB.java ├── 2_maximum_pairwise_product │ └── MaxPairwiseProduct.java └── week1_programming_challenges.pdf ├── week2_algorithmic_warmup ├── 1_fibonacci_number │ └── Fibonacci.java ├── 2_last_digit_of_fibonacci_number │ └── FibonacciLastDigit.java ├── 3_greatest_common_divisor │ └── GCD.java ├── 4_least_common_multiple │ └── LCM.java ├── 5_fibonacci_number_again │ └── FibonacciHuge.java ├── 6_last_digit_of_the_sum_of_fibonacci_numbers │ └── FibonacciSumLastDigit.java ├── 7_last_digit_of_the_sum_of_fibonacci_numbers_again │ ├── FibonacciPartialSum.class │ ├── FibonacciPartialSum.java │ ├── by_learners │ │ └── fib_partial_sum.rb │ ├── fibonacci_partial_sum.cpp │ ├── fibonacci_partial_sum.hs │ └── fibonacci_partial_sum.py └── week2_algorithmic_warmup.pdf ├── week3_greedy_algorithms ├── 1_money_change │ └── change.py ├── 2_maximum_value_of_the_loot │ └── fractional_knapsack.py ├── 3_maximum_advertisement_revenue │ └── dot_product.py ├── 4_collecting_signatures │ ├── covering_segments.py │ └── covering_segments_short.py ├── 5_maximum_number_of_prizes │ └── different_summands.py ├── 6_maximum_salary │ └── largest_number.py └── week3_greedy_algorithms.pdf ├── week4_divide_and_conquer ├── 1_binary_search │ └── binary_search.py ├── 2_majority_element │ └── majority_element.py ├── 3_improving_quicksort │ └── sorting.py ├── 4_number_of_inversions │ └── inversions.py ├── 5_organizing_a_lottery │ └── points_and_segments.py ├── 6_closest_points │ └── closest.py └── week4_divide_and_conquer.pdf ├── week5_dynamic_programming1 ├── 1_money_change_again │ └── change_dp.py ├── 2_primitive_calculator │ └── primitive_calculator.py ├── 3_edit_distance │ └── edit_distance.py ├── 4_longest_common_subsequence_of_two_sequences │ └── lcs2.py ├── 5_longest_common_subsequence_of_three_sequences │ └── lcs3.py └── week5_dynamic_programming1.pdf └── week6_dynamic_programming2 ├── 1_maximum_amount_of_gold └── knapsack.py ├── 2_partitioning_souvenirs └── partition3.py ├── 3_maximum_value_of_an_arithmetic_expression └── placing_parentheses.py └── week6_dynamic_programming2.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | 4 | # User-specific stuff: 5 | .idea/**/workspace.xml 6 | .idea/**/tasks.xml 7 | .idea/dictionaries 8 | .idea 9 | 10 | # Sensitive or high-churn files: 11 | .idea/**/dataSources/ 12 | .idea/**/dataSources.ids 13 | .idea/**/dataSources.local.xml 14 | .idea/**/sqlDataSources.xml 15 | .idea/**/dynamic.xml 16 | .idea/**/uiDesigner.xml 17 | 18 | # Gradle: 19 | .idea/**/gradle.xml 20 | .idea/**/libraries 21 | 22 | # CMake 23 | cmake-build-debug/ 24 | cmake-build-release/ 25 | 26 | # Mongo Explorer plugin: 27 | .idea/**/mongoSettings.xml 28 | 29 | ## File-based project format: 30 | *.iws 31 | 32 | ## Plugin-specific files: 33 | 34 | # IntelliJ 35 | out/ 36 | 37 | # mpeltonen/sbt-idea plugin 38 | .idea_modules/ 39 | 40 | # JIRA plugin 41 | atlassian-ide-plugin.xml 42 | 43 | # Cursive Clojure plugin 44 | .idea/replstate.xml 45 | 46 | # Crashlytics plugin (for Android Studio and IntelliJ) 47 | com_crashlytics_export_strings.xml 48 | crashlytics.properties 49 | crashlytics-build.properties 50 | fabric.properties 51 | 52 | .DS_Store 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithmic-toolbox 2 | About this Course 3 | The course covers basic algorithmic techniques and ideas for computational problems arising frequently in practical applications: sorting and searching, divide and conquer, greedy algorithms, dynamic programming. We will learn a lot of theory: how to sort data and how it helps for searching; how to break a large problem into pieces and solve them recursively; when it makes sense to proceed greedily; how dynamic programming is used in genomic studies. You will practice solving computational problems, designing new algorithms, and implementing solutions efficiently (so that they run in less than a second). -------------------------------------------------------------------------------- /week1_programming_challenges/1_sum_of_two_digits/APlusB.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | 3 | class APlusB { 4 | public static void main(String[] args) { 5 | Scanner s = new Scanner(System.in); 6 | int a = s.nextInt(); 7 | int b = s.nextInt(); 8 | System.out.println(a + b); 9 | } 10 | } -------------------------------------------------------------------------------- /week1_programming_challenges/2_maximum_pairwise_product/MaxPairwiseProduct.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.io.*; 3 | 4 | public class MaxPairwiseProduct { 5 | static int getMaxPairwiseProduct(int[] numbers) { 6 | int result = 0; 7 | int n = numbers.length; 8 | for (int i = 0; i < n; ++i) { 9 | for (int j = i + 1; j < n; ++j) { 10 | if (numbers[i] * numbers[j] > result) { 11 | result = numbers[i] * numbers[j]; 12 | } 13 | } 14 | } 15 | return result; 16 | } 17 | 18 | public static void main(String[] args) { 19 | FastScanner scanner = new FastScanner(System.in); 20 | int n = scanner.nextInt(); 21 | int[] numbers = new int[n]; 22 | for (int i = 0; i < n; i++) { 23 | numbers[i] = scanner.nextInt(); 24 | } 25 | System.out.println(getMaxPairwiseProduct(numbers)); 26 | } 27 | 28 | static class FastScanner { 29 | BufferedReader br; 30 | StringTokenizer st; 31 | 32 | FastScanner(InputStream stream) { 33 | try { 34 | br = new BufferedReader(new InputStreamReader(stream)); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | String next() { 41 | while (st == null || !st.hasMoreTokens()) { 42 | try { 43 | st = new StringTokenizer(br.readLine()); 44 | } catch (IOException e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | return st.nextToken(); 49 | } 50 | 51 | int nextInt() { 52 | return Integer.parseInt(next()); 53 | } 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /week1_programming_challenges/week1_programming_challenges.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmelnyk/Algorithmic-toolbox/4120c988a19803409c796839903ff5e0553d0d6b/week1_programming_challenges/week1_programming_challenges.pdf -------------------------------------------------------------------------------- /week2_algorithmic_warmup/1_fibonacci_number/Fibonacci.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | 3 | public class Fibonacci { 4 | private static int[] intArr = new int[50]; 5 | 6 | private static long calc_fib(int n) { 7 | intArr[0] = 0; 8 | intArr[1] = 1; 9 | for (int i = 2 ;i <= n; i++) { 10 | intArr[i] = intArr[i-1]+ intArr[i-2]; 11 | } 12 | return intArr[n]; 13 | } 14 | 15 | public static void main(String args[]) { 16 | Scanner in = new Scanner(System.in); 17 | int n = in.nextInt(); 18 | 19 | System.out.println(calc_fib(n)); 20 | } 21 | } -------------------------------------------------------------------------------- /week2_algorithmic_warmup/2_last_digit_of_fibonacci_number/FibonacciLastDigit.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class FibonacciLastDigit { 4 | private static int getFibonacciLastDigitNaive(int n) { 5 | if (n <= 1) 6 | return n; 7 | 8 | int previous = 0; 9 | int current = 1; 10 | 11 | for (int i = 0; i < n - 1; ++i) { 12 | int tmp_previous = previous; 13 | previous = current; 14 | current = (tmp_previous + current) % 10; 15 | } 16 | 17 | return current % 10; 18 | } 19 | 20 | public static void main(String[] args) { 21 | Scanner scanner = new Scanner(System.in); 22 | int n = scanner.nextInt(); 23 | int c = getFibonacciLastDigitNaive(n); 24 | System.out.println(c); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/3_greatest_common_divisor/GCD.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class GCD { 4 | 5 | private static int gcd_euclidian(int a, int b) { 6 | int c = 1; 7 | while (b != 0){ 8 | c = a % b; 9 | a = b; 10 | b = c; 11 | } 12 | return a; 13 | } 14 | 15 | 16 | public static void main(String args[]) { 17 | Scanner scanner = new Scanner(System.in); 18 | int a = scanner.nextInt(); 19 | int b = scanner.nextInt(); 20 | 21 | System.out.println(gcd_euclidian(a, b)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/4_least_common_multiple/LCM.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class LCM { 4 | private static int gcd_euclidian(int a, int b) { 5 | int c = 1; 6 | while (b != 0){ 7 | c = a % b; 8 | a = b; 9 | b = c; 10 | } 11 | return a; 12 | } 13 | 14 | private static long lcm_fast(int a, int b) { 15 | return ((long)a * b) / (gcd_euclidian(a,b)); 16 | } 17 | 18 | public static void main(String args[]) { 19 | Scanner scanner = new Scanner(System.in); 20 | int a = scanner.nextInt(); 21 | int b = scanner.nextInt(); 22 | 23 | System.out.println(lcm_fast(a, b)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/5_fibonacci_number_again/FibonacciHuge.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class FibonacciHuge { 4 | private static long getFibonacciLastDigitNaive(long n, long m) { 5 | if (n <= 1) 6 | return n; 7 | 8 | long previous = 0L; 9 | long current = 1L; 10 | 11 | for (long i = 0; i < n - 1; ++i) { 12 | long tmp_previous = previous; 13 | previous = current; 14 | current = (tmp_previous + current) % m; 15 | } 16 | 17 | return current; 18 | } 19 | 20 | private static long getFibonacciHuge(long n, long m) { 21 | 22 | // long b = System.currentTimeMillis(); 23 | int pisanoPeriodLength = getPisanoPeriodLength(m); 24 | // System.out.println("pisano " +pisanoPeriodLength); 25 | // long c = System.currentTimeMillis(); 26 | 27 | // System.out.println("time : "+ (c-b)); 28 | 29 | int index = (int) ((long)n % (long) pisanoPeriodLength); 30 | 31 | return getFibonacciLastDigitNaive(index, m); 32 | } 33 | 34 | private static int getPisanoPeriodLength(long m) { 35 | 36 | long a = 0L; 37 | long b = 1L; 38 | long c = a + b; 39 | for (int i = 0; i < m * m; i++) { 40 | c = (a + b) % m; 41 | a = b; 42 | b = c; 43 | if (a == 0L && b == 1L) { 44 | return i + 1; 45 | } 46 | } 47 | return 0; 48 | } 49 | 50 | 51 | public static void main(String[] args) { 52 | Scanner scanner = new Scanner(System.in); 53 | long n = scanner.nextLong(); 54 | long m = scanner.nextLong(); 55 | System.out.println(getFibonacciHuge(n,m)); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/6_last_digit_of_the_sum_of_fibonacci_numbers/FibonacciSumLastDigit.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class FibonacciSumLastDigit { 4 | 5 | private static long getFibonacciSumFast(long n) { 6 | if (n <= 1) 7 | return n; 8 | 9 | n +=2; 10 | return getFibonacciHuge(n,10); 11 | } 12 | 13 | private static long getFibonacciHuge(long n, long m) { 14 | 15 | long pisanoPeriodLength = 60L; 16 | 17 | long index = (n % pisanoPeriodLength); 18 | 19 | return getFibonacciLastDigitNaive(index, m); 20 | } 21 | 22 | private static int getPisanoPeriodLength(long m) { 23 | 24 | long a = 0L; 25 | long b = 1L; 26 | long c = a + b; 27 | for (int i = 0; i < m * m; i++) { 28 | c = (a + b) % m; 29 | a = b; 30 | b = c; 31 | if (a == 0L && b == 1L) { 32 | return i + 1; 33 | } 34 | } 35 | return 0; 36 | } 37 | 38 | private static long getFibonacciLastDigitNaive(long n, long m) { 39 | if (n <= 1) 40 | return 0 ; 41 | 42 | long previous = 0L; 43 | long current = 1L; 44 | 45 | for (long i = 0; i < n - 1; ++i) { 46 | long tmp_previous = previous; 47 | previous = current; 48 | if(i != n-2){ 49 | current = (tmp_previous + current) % m; 50 | } 51 | else{ 52 | current = (tmp_previous + current -1) % m; 53 | } 54 | } 55 | 56 | return current; 57 | } 58 | 59 | 60 | public static void main(String[] args) { 61 | // 0 1 1 2 3 5 8 13 21 34 62 | // 0 1 2 4 7 12 20 33 54 88 63 | Scanner scanner = new Scanner(System.in); 64 | long n = scanner.nextLong(); 65 | // long s = getFibonacciSumNaive(n); 66 | long s2 = getFibonacciSumFast(n); 67 | // System.out.println(s); 68 | System.out.println(s2); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/7_last_digit_of_the_sum_of_fibonacci_numbers_again/FibonacciPartialSum.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmelnyk/Algorithmic-toolbox/4120c988a19803409c796839903ff5e0553d0d6b/week2_algorithmic_warmup/7_last_digit_of_the_sum_of_fibonacci_numbers_again/FibonacciPartialSum.class -------------------------------------------------------------------------------- /week2_algorithmic_warmup/7_last_digit_of_the_sum_of_fibonacci_numbers_again/FibonacciPartialSum.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class FibonacciPartialSum { 4 | 5 | private static long getFibonacciLastDigitFastSimple(long n, long m) { 6 | 7 | long pisanoPeriodLength = 60L; 8 | 9 | long index = (n % pisanoPeriodLength); 10 | 11 | n = index; 12 | if (n < 1){ 13 | return 0 ; 14 | } 15 | if (n ==1){ 16 | return 1 ; 17 | } 18 | 19 | long previous = 0L; 20 | long current = 1L; 21 | 22 | for (long i = 0; i < n - 1; ++i) { 23 | long tmp_previous = previous; 24 | previous = current; 25 | 26 | current = (tmp_previous + current) %10 ; 27 | } 28 | return current; 29 | } 30 | private static long getFibonacciSumFast(long n) { 31 | if( n <=0L){ 32 | return 0L; 33 | } 34 | if (n == 1L) 35 | return 1L; 36 | 37 | n += 2; 38 | 39 | return getFibonacciHuge(n,10); 40 | } 41 | 42 | private static long getFibonacciHuge(long n, long m) { 43 | 44 | long pisanoPeriodLength = 60L; 45 | 46 | long index = (n % pisanoPeriodLength); 47 | 48 | return getFibonacciLastDigitFast(index, m); 49 | } 50 | 51 | private static long getFibonacciLastDigitFast(long n, long m) { 52 | if (n <= 1) 53 | return 0 ; 54 | 55 | long previous = 0L; 56 | long current = 1L; 57 | 58 | for (long i = 0; i < n - 1; ++i) { 59 | long tmp_previous = previous; 60 | previous = current; 61 | if(i != n-2){ 62 | current = (tmp_previous + current) % 10 ; 63 | } 64 | else{ 65 | current = (tmp_previous + current -1) % 10; 66 | } 67 | } 68 | 69 | return current; 70 | } 71 | 72 | 73 | 74 | private static long getFibonacciPartialSumFast(long from, long to){ 75 | if(from == to){ 76 | return getFibonacciLastDigitFastSimple(to, 10) % 10; 77 | } 78 | if (from == 0){ 79 | return getFibonacciSumFast(to); 80 | } 81 | long modSumFrom = getFibonacciSumFast(from-1); 82 | long modSumTo = getFibonacciSumFast(to); 83 | // System.out.println(modSumFrom); 84 | // System.out.println(modSumTo); 85 | long result = modSumTo - modSumFrom ; 86 | if(result < 0){ 87 | result = 10 + result; 88 | } 89 | return result; 90 | 91 | 92 | } 93 | 94 | public static void main(String[] args) { 95 | Scanner scanner = new Scanner(System.in); 96 | long from = scanner.nextLong(); 97 | long to = scanner.nextLong(); 98 | System.out.println(getFibonacciPartialSumFast(from, to)); 99 | } 100 | } 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/7_last_digit_of_the_sum_of_fibonacci_numbers_again/by_learners/fib_partial_sum.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # by Andronik Ordian 3 | 4 | def fib_partial_sum(m, n) 5 | # write your code here 6 | 0 7 | end 8 | 9 | if __FILE__ == $0 10 | m, n = gets.split().map(&:to_i) 11 | puts "#{fib_partial_sum(m, n)}" 12 | end 13 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/7_last_digit_of_the_sum_of_fibonacci_numbers_again/fibonacci_partial_sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using std::vector; 4 | 5 | long long get_fibonacci_partial_sum_naive(long long from, long long to) { 6 | long long sum = 0; 7 | 8 | long long current = 0; 9 | long long next = 1; 10 | 11 | for (long long i = 0; i <= to; ++i) { 12 | if (i >= from) { 13 | sum += current; 14 | } 15 | 16 | long long new_current = next; 17 | next = next + current; 18 | current = new_current; 19 | } 20 | 21 | return sum % 10; 22 | } 23 | 24 | int main() { 25 | long long from, to; 26 | std::cin >> from >> to; 27 | std::cout << get_fibonacci_partial_sum_naive(from, to) << '\n'; 28 | } 29 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/7_last_digit_of_the_sum_of_fibonacci_numbers_again/fibonacci_partial_sum.hs: -------------------------------------------------------------------------------- 1 | -- by Kirill Elagin 2 | 3 | fibonacci_partial_sum_naive :: Integer -> Integer -> Int 4 | fibonacci_partial_sum_naive from to = let (a', b', _) = helper (0, 1, 0) from 5 | (_, _, s) = helper (a', b', a') (to - from) 6 | in s 7 | where 8 | helper (a, b, s) 0 = (a, b, s `mod` 10) 9 | helper (a, b, s) i = helper (b, a + b, s + b) (i - 1) 10 | 11 | main :: IO () 12 | main = do 13 | [from, to] <- fmap words getLine 14 | print $ fibonacci_partial_sum_naive (read from) (read to) 15 | -------------------------------------------------------------------------------- /week2_algorithmic_warmup/7_last_digit_of_the_sum_of_fibonacci_numbers_again/fibonacci_partial_sum.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | def fibonacci_partial_sum_naive(from_, to): 5 | sum = 0 6 | 7 | current = 0 8 | next = 1 9 | 10 | for i in range(to + 1): 11 | if i >= from_: 12 | sum += current 13 | 14 | current, next = next, current + next 15 | 16 | return sum % 10 17 | 18 | 19 | if __name__ == '__main__': 20 | input = sys.stdin.read(); 21 | from_, to = map(int, input.split()) 22 | print(fibonacci_partial_sum_naive(from_, to)) -------------------------------------------------------------------------------- /week2_algorithmic_warmup/week2_algorithmic_warmup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmelnyk/Algorithmic-toolbox/4120c988a19803409c796839903ff5e0553d0d6b/week2_algorithmic_warmup/week2_algorithmic_warmup.pdf -------------------------------------------------------------------------------- /week3_greedy_algorithms/1_money_change/change.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | def get_change(m): 5 | big = 10 6 | medium = 5 7 | small = 1 8 | result = 0 9 | 10 | coins = [big, medium, small] 11 | 12 | while m != 0: 13 | for coin in coins: 14 | if (m - coin >= 0): 15 | m -= coin 16 | result = result+1 17 | break 18 | 19 | 20 | 21 | return result 22 | 23 | if __name__ == '__main__': 24 | m = int(sys.stdin.readline()) 25 | print(get_change(m)) 26 | -------------------------------------------------------------------------------- /week3_greedy_algorithms/2_maximum_value_of_the_loot/fractional_knapsack.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | 5 | class Item: 6 | value = 0. 7 | weight = 0. 8 | vw_ratio = 0. 9 | 10 | def __init__(self, value, weight, vw_ratio): 11 | self.value = value 12 | self.weight = weight 13 | self.vw_ratio = vw_ratio 14 | 15 | 16 | def get_items(values, weights): 17 | return [Item(values[i], weights[i], values[i] / weights[i]) for i in range(len(values))] 18 | 19 | 20 | def get_optimal_value(capacity, weights, values): 21 | value = 0. 22 | items = get_items(values, weights) 23 | items.sort(key=lambda obj: obj.vw_ratio) 24 | 25 | while capacity > 0 and len(items) != 0: 26 | item = items.pop() 27 | weight = min(item.weight, capacity) 28 | value += weight * (item.vw_ratio) 29 | item.weight -= weight 30 | capacity -= weight 31 | 32 | return value 33 | 34 | 35 | if __name__ == "__main__": 36 | data = list(map(int, sys.stdin.read().split())) 37 | n, capacity = data[0:2] 38 | values = data[2:(2 * n + 2):2] 39 | weights = data[3:(2 * n + 2):2] 40 | opt_value = get_optimal_value(capacity, weights, values) 41 | print("{:.10f}".format(opt_value)) 42 | -------------------------------------------------------------------------------- /week3_greedy_algorithms/3_maximum_advertisement_revenue/dot_product.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | 3 | import sys 4 | 5 | def max_dot_product(a, b): 6 | c = [] 7 | for i in range(len(a)): 8 | for j in range(len(b)): 9 | c.append((a[i] * b[j])) 10 | 11 | c.sort() 12 | c = c[-len(a):] 13 | 14 | return sum(c) 15 | def max_dot_product_fast(a, b): 16 | a.sort() 17 | b.sort() 18 | 19 | c = [] 20 | for i in range(len(a)): 21 | c.append(a.pop()*b.pop()) 22 | 23 | return sum(c) 24 | 25 | if __name__ == '__main__': 26 | input = sys.stdin.read() 27 | data = list(map(int, input.split())) 28 | n = data[0] 29 | a = data[1:(n + 1)] 30 | b = data[(n + 1):] 31 | print(max_dot_product_fast(a, b)) 32 | -------------------------------------------------------------------------------- /week3_greedy_algorithms/4_collecting_signatures/covering_segments.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | from collections import namedtuple 4 | 5 | Segment = namedtuple('Segment', 'start end') 6 | 7 | 8 | def optimal_points(segments): 9 | segments.sort(key=lambda obj: obj.end, reverse=True) 10 | points = [] 11 | # write your code here 12 | tmp_point = 0 13 | # print(segments) 14 | while len(segments) != 0: 15 | base_segment = segments.pop() 16 | tmp_point = base_segment.end 17 | while len(segments) != 0 and segments[-1].start <= tmp_point: 18 | # print(base_segment, segments[-1], tmp_point) 19 | segments.pop() 20 | 21 | if(tmp_point not in points): 22 | points.append(tmp_point) 23 | 24 | points.sort() 25 | return points 26 | 27 | 28 | if __name__ == '__main__': 29 | input = sys.stdin.read() 30 | n, *data = map(int, input.split()) 31 | segments = list(map(lambda x: Segment(x[0], x[1]), zip(data[::2], data[1::2]))) 32 | points = optimal_points(segments) 33 | print(len(points)) 34 | for p in points: 35 | print(p, end=' ') 36 | -------------------------------------------------------------------------------- /week3_greedy_algorithms/4_collecting_signatures/covering_segments_short.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | from collections import namedtuple 4 | 5 | Segment = namedtuple('Segment', 'start end') 6 | 7 | 8 | def optimal_points(segments): 9 | segments.sort(key=lambda obj: obj.start, reverse=True) 10 | points = [] 11 | # write your code here 12 | tmp_point = 0 13 | # print(segments) 14 | while len(segments) != 0: 15 | base_segment = segments.pop() 16 | tmp_point = base_segment.start 17 | if(len(segments) != 0 and segments[-1].start <= base_segment.end ): 18 | 19 | if(segments[-1].end < base_segment.end): 20 | tmp_point = segments.pop().end 21 | else: 22 | segments.pop() 23 | tmp_point = base_segment.end 24 | if(tmp_point not in points): 25 | points.append(tmp_point) 26 | 27 | points.sort() 28 | return points 29 | 30 | 31 | if __name__ == '__main__': 32 | input = sys.stdin.read() 33 | n, *data = map(int, input.split()) 34 | segments = list(map(lambda x: Segment(x[0], x[1]), zip(data[::2], data[1::2]))) 35 | points = optimal_points(segments) 36 | print(len(points)) 37 | for p in points: 38 | print(p, end=' ') 39 | -------------------------------------------------------------------------------- /week3_greedy_algorithms/5_maximum_number_of_prizes/different_summands.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | 5 | def optimal_summands(n): 6 | summands = [] 7 | # write your code here 8 | i = 1 9 | sum_summands = 0 10 | while sum_summands <= n: 11 | if (sum_summands + i) <= n: 12 | summands.append(i) 13 | sum_summands += i 14 | else: 15 | summands[-1] += n - sum_summands 16 | break 17 | i = i + 1 18 | 19 | return summands 20 | 21 | 22 | if __name__ == '__main__': 23 | input = sys.stdin.read() 24 | n = int(input) 25 | summands = optimal_summands(n) 26 | print(len(summands)) 27 | for x in summands: 28 | print(x, end=' ') 29 | -------------------------------------------------------------------------------- /week3_greedy_algorithms/6_maximum_salary/largest_number.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | 3 | import sys 4 | 5 | import math 6 | 7 | 8 | def is_greater(digit, max_digit): 9 | return digit + max_digit > max_digit + digit 10 | 11 | 12 | def largest_number(digits): 13 | # write your code here 14 | res = "" 15 | 16 | while len(digits) != 0: 17 | max_digit = '0' 18 | for digit in digits: 19 | # print("digit str ", digit_str) 20 | if is_greater(digit, max_digit): 21 | max_digit = digit 22 | # print("max", max_digit) 23 | res += max_digit 24 | # print(max_digit) 25 | digits.remove(max_digit) 26 | return res 27 | 28 | 29 | if __name__ == '__main__': 30 | input = sys.stdin.read() 31 | data = input.split() 32 | digits = data[1:] 33 | print(largest_number(digits)) 34 | -------------------------------------------------------------------------------- /week3_greedy_algorithms/week3_greedy_algorithms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmelnyk/Algorithmic-toolbox/4120c988a19803409c796839903ff5e0553d0d6b/week3_greedy_algorithms/week3_greedy_algorithms.pdf -------------------------------------------------------------------------------- /week4_divide_and_conquer/1_binary_search/binary_search.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | 5 | def binary_search(array, fromIndex, toIndex, searchableNumber): 6 | if toIndex < fromIndex: 7 | return - 1 8 | 9 | midIndex = fromIndex + (toIndex - fromIndex) // 2 10 | 11 | if searchableNumber == array[midIndex]: 12 | return midIndex 13 | elif searchableNumber < array[midIndex]: 14 | return binary_search(array, fromIndex, midIndex - 1, searchableNumber) 15 | else: 16 | return binary_search(array, midIndex + 1, toIndex, searchableNumber) 17 | 18 | 19 | def find_in_initial_array(initalArray, targetArray): 20 | initalArray.sort() 21 | 22 | array_of_indexes = [] 23 | for searchableNumber in targetArray: 24 | array_of_indexes.append(str(binary_search(initalArray, 0, len(initalArray) - 1, searchableNumber))) 25 | return array_of_indexes 26 | 27 | 28 | if __name__ == '__main__': 29 | input = sys.stdin.read() 30 | data = list(map(int, input.split())) 31 | n = data[0] 32 | m = data[n + 1] 33 | a = data[1: n + 1] 34 | x = data[n + 2:] 35 | # replace with the call to binary_search when implemented 36 | print(' '.join(find_in_initial_array(a, x))) 37 | -------------------------------------------------------------------------------- /week4_divide_and_conquer/2_majority_element/majority_element.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | 5 | def get_majority_element(a, left, right): 6 | if left == right: 7 | return -1 8 | if left + 1 == right: 9 | return a[left] 10 | 11 | leftMajority = get_majority_element(a, left, (left + right - 1) // 2 + 1) 12 | rightMajority = get_majority_element(a, (left + right - 1) // 2 + 1, right) 13 | 14 | left_count = 0 15 | for i in range(left, right): 16 | if a[i] == leftMajority: 17 | left_count += 1 18 | if left_count > (right - left) // 2: 19 | return leftMajority 20 | 21 | right_count = 0 22 | for i in range(left, right): 23 | if a[i] == rightMajority: 24 | right_count += 1 25 | if right_count > (right - left) // 2: 26 | return rightMajority 27 | 28 | return -1 29 | 30 | 31 | if __name__ == '__main__': 32 | input = sys.stdin.read() 33 | n, *a = list(map(int, input.split())) 34 | if get_majority_element(a, 0, n) != -1: 35 | print(1) 36 | else: 37 | print(0) 38 | 39 | -------------------------------------------------------------------------------- /week4_divide_and_conquer/3_improving_quicksort/sorting.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | import random 4 | 5 | 6 | def partition3(a, l, r): 7 | x = a[l] 8 | j = l 9 | i = l 10 | while i <= r: 11 | if a[i] < x: 12 | a[i], a[j] = a[j], a[i] 13 | j += 1 14 | i += 1 15 | elif a[i] > x: 16 | a[i], a[r] = a[r], a[i] 17 | r -= 1 18 | else: 19 | i += 1 20 | 21 | return [j ,r] 22 | 23 | 24 | def randomized_quick_sort(a, l, r): 25 | if l >= r: 26 | return 27 | k = random.randint(l, r) 28 | a[l], a[k] = a[k], a[l] 29 | # use partition3 30 | m = partition3(a, l, r) 31 | randomized_quick_sort(a, l, m[0] - 1) 32 | randomized_quick_sort(a, m[1] + 1, r) 33 | 34 | 35 | if __name__ == '__main__': 36 | input = sys.stdin.read() 37 | n, *a = list(map(int, input.split())) 38 | randomized_quick_sort(a, 0, n - 1) 39 | for x in a: 40 | print(x, end=' ') 41 | -------------------------------------------------------------------------------- /week4_divide_and_conquer/4_number_of_inversions/inversions.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | 5 | def merge(a, b, left, ave, right): 6 | number_of_inversions = 0 7 | i, j, k = left, ave, left 8 | while i <= ave - 1 and j <= right: 9 | if a[i] <= a[j]: 10 | b[k] = a[i] 11 | i += 1 12 | else: 13 | b[k] = a[j] 14 | j += 1 15 | number_of_inversions += ave - i 16 | k += 1 17 | while i <= ave - 1: 18 | b[k] = a[i] 19 | i += 1 20 | k += 1 21 | while j <= right: 22 | b[k] = a[j] 23 | j += 1 24 | k += 1 25 | for i in range(left, right + 1): 26 | a[i] = b[i] 27 | return number_of_inversions 28 | 29 | 30 | def get_number_of_inversions(a, b, left, right): 31 | number_of_inversions = 0 32 | if right <= left: 33 | return number_of_inversions 34 | ave = (left + right) // 2 35 | number_of_inversions += get_number_of_inversions(a, b, left, ave) 36 | number_of_inversions += get_number_of_inversions(a, b, ave + 1, right) 37 | number_of_inversions += merge(a, b, left, ave + 1, right) 38 | 39 | return number_of_inversions 40 | 41 | 42 | if __name__ == '__main__': 43 | input = sys.stdin.read() 44 | n, *a = list(map(int, input.split())) 45 | b = n * [0] 46 | print(get_number_of_inversions(a, b, 0, len(a)-1)) 47 | -------------------------------------------------------------------------------- /week4_divide_and_conquer/5_organizing_a_lottery/points_and_segments.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | from collections import namedtuple 4 | from itertools import chain 5 | 6 | Segment = namedtuple('Segment', 'start end') 7 | 8 | 9 | def fast_count_segments(starts, ends, points): 10 | cnt = [0] * len(points) 11 | starts = zip(starts, ['l'] * len(starts), range(len(starts))) 12 | ends = zip(ends, ['r'] * len(ends), range(len(ends))) 13 | points = zip(points, ['p'] * len(points), range(len(points))) 14 | 15 | sort_list = chain(starts, ends, points) 16 | sort_list = sorted(sort_list) 17 | i = 0 18 | for num, letter, index in sort_list: 19 | if letter == 'l': 20 | i += 1 21 | elif letter == 'r': 22 | i -= 1 23 | else: 24 | cnt[index] = i 25 | return cnt 26 | 27 | 28 | def naive_count_segments(starts, ends, points): 29 | cnt = [0] * len(points) 30 | for i in range(len(points)): 31 | for j in range(len(starts)): 32 | if starts[j] <= points[i] <= ends[j]: 33 | cnt[i] += 1 34 | return cnt 35 | 36 | 37 | if __name__ == '__main__': 38 | input = sys.stdin.read() 39 | data = list(map(int, input.split())) 40 | n = data[0] 41 | m = data[1] 42 | segments = list(map(lambda x: Segment(x[0], x[1]), zip(data[2:2 * n + 2:2], data[3:2 * n + 2:2]))) 43 | ends = data[3:2 * n + 2:2] 44 | starts = data[2:2 * n + 2:2] 45 | points = data[2 * n + 2:] 46 | # use fast_count_segments 47 | # cnt = naive_count_segments(starts, ends, points) 48 | cnt = fast_count_segments(starts, ends, points) 49 | # cnt = fast_count_segments([-3, 0, 7], [2, 5, 10], [1, 6]) 50 | for x in cnt: 51 | print(x, end=' ') 52 | -------------------------------------------------------------------------------- /week4_divide_and_conquer/6_closest_points/closest.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import math 3 | import random 4 | 5 | import sys 6 | 7 | 8 | def solution(x, y): 9 | points = list(zip(x, y)) 10 | points_x_sorted = sorted(points, key=lambda obj: obj[0]) 11 | points_y_sorted = sorted(points, key=lambda obj: obj[1]) 12 | d = minimum_points_distance(points_x_sorted, points_y_sorted) 13 | return d 14 | 15 | 16 | def minimum_points_distance(points_x_sorted, points_y_sorted): 17 | ln_ax = len(points_x_sorted) 18 | if ln_ax <= 3: 19 | return brute(points_x_sorted) 20 | mid = ln_ax // 2 21 | points_x_sorted_left = points_x_sorted[:mid] 22 | points_x_sorted_right = points_x_sorted[mid:] 23 | points_x_sorted_set = set(points_x_sorted_left) 24 | points_y_sorted_left = list() 25 | points_y_sorted_right = list() 26 | for point in points_y_sorted: 27 | if point in points_x_sorted_set: 28 | points_y_sorted_left.append(point) 29 | else: 30 | points_y_sorted_right.append(point) 31 | d1 = minimum_points_distance(points_x_sorted_left, points_y_sorted_left) 32 | d2 = minimum_points_distance(points_x_sorted_right, points_y_sorted_right) 33 | d = min(d1, d2) 34 | d3 = closest_split_pair(points_x_sorted, points_y_sorted, d) 35 | return min(d3, d) 36 | 37 | 38 | def brute(points_x_sorted): 39 | mi = calc_dist(points_x_sorted[0], points_x_sorted[1]) 40 | ln_ax = len(points_x_sorted) 41 | if ln_ax == 2: 42 | return mi 43 | for i in range(ln_ax - 1): 44 | for j in range(i + 1, ln_ax): 45 | if i != 0 or j != 1: 46 | d = calc_dist(points_x_sorted[i], points_x_sorted[j]) 47 | if d < mi: 48 | mi = d 49 | return mi 50 | 51 | 52 | def calc_dist(point1, point2): 53 | return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) 54 | 55 | 56 | def closest_split_pair(points_x_sorted, points_y_sorted, delta): 57 | ln_x = len(points_x_sorted) 58 | mx_x = points_x_sorted[ln_x // 2][0] 59 | s_y = [x for x in points_y_sorted if mx_x - delta <= x[0] <= mx_x + delta] 60 | best = delta 61 | ln_y = len(s_y) 62 | for i in range(ln_y - 1): 63 | for j in range(i + 1, min(i + 7, ln_y)): 64 | p, q = s_y[i], s_y[j] 65 | dst = calc_dist(p, q) 66 | if dst < best: 67 | best = dst 68 | return best 69 | 70 | 71 | def test_case(length: int = 10000): 72 | lst1 = [random.randint(-10 ** 9, 10 ** 9) for i in range(length)] 73 | lst2 = [random.randint(-10 ** 9, 10 ** 9) for i in range(length)] 74 | return lst1, lst2 75 | 76 | 77 | if __name__ == '__main__': 78 | input = sys.stdin.read() 79 | data = list(map(int, input.split())) 80 | n = data[0] 81 | x = data[1::2] 82 | y = data[2::2] 83 | # x, y = test_case() 84 | # start = time.time() 85 | print("{0:.9f}".format(solution(x, y))) 86 | # print(time.time() - start) 87 | -------------------------------------------------------------------------------- /week4_divide_and_conquer/week4_divide_and_conquer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmelnyk/Algorithmic-toolbox/4120c988a19803409c796839903ff5e0553d0d6b/week4_divide_and_conquer/week4_divide_and_conquer.pdf -------------------------------------------------------------------------------- /week5_dynamic_programming1/1_money_change_again/change_dp.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | from math import inf 4 | 5 | 6 | def get_change(m): 7 | # write your code here 8 | coins = [1, 3, 4] 9 | 10 | min_number_of_coins = [None] * (m + 1) 11 | 12 | min_number_of_coins[0] = 0 13 | 14 | for i in range(1, m + 1): 15 | min_number_of_coins[i] = inf 16 | for whole_coin in coins: 17 | if i >= whole_coin: 18 | tmp = min_number_of_coins[i - whole_coin] + 1 19 | if tmp < min_number_of_coins[i]: 20 | min_number_of_coins[i] = tmp 21 | else: 22 | break 23 | 24 | return min_number_of_coins[m] 25 | 26 | 27 | if __name__ == '__main__': 28 | m = int(sys.stdin.read()) 29 | print(get_change(m)) 30 | -------------------------------------------------------------------------------- /week5_dynamic_programming1/2_primitive_calculator/primitive_calculator.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | from math import inf 4 | 5 | 6 | def func1(x): return (int)(x - 1) 7 | 8 | 9 | def func2(x): return (int)(x / 2) 10 | 11 | 12 | def func3(x): return (int)(x / 3) 13 | 14 | 15 | actions = [func1, func2, func3] 16 | 17 | 18 | def optimal_sequence(m): 19 | min_sequence = [None] * (m + 1) 20 | 21 | min_sequence[0] = 0 22 | min_sequence[1] = 0 23 | 24 | sequence = [] 25 | sequence.append([0]) 26 | sequence.append([1]) 27 | 28 | # 1 2 3 4 5 6 7 8 9 10 29 | # 1 1 1 2 3 2 3 3 2 3 30 | for i in range(2, m + 1): 31 | min_sequence[i] = inf 32 | tmp2 = inf 33 | tmp3 = inf 34 | if (i % 3 == 0): 35 | tmp3 = min_sequence[func3(i)] + 1 36 | if (i % 2 == 0): 37 | tmp2 = min_sequence[func2(i)] + 1 38 | tmp1 = min_sequence[i - 1] + 1 39 | 40 | min_tmp = min(tmp1, tmp2, tmp3) 41 | 42 | min_sequence[i] = min_tmp 43 | if min_tmp == tmp1: 44 | sequence.append(sequence[func1(i)] + [i]) 45 | continue 46 | if min_tmp == tmp2: 47 | sequence.append(sequence[func2(i)] + [i]) 48 | continue 49 | if min_tmp == tmp3: 50 | sequence.append(sequence[func3(i)] + [i]) 51 | 52 | return sequence[-1] 53 | 54 | 55 | if __name__ == '__main__': 56 | input = sys.stdin.read() 57 | n = int(input) 58 | sequence = list(optimal_sequence(n)) 59 | print(len(sequence) - 1) 60 | for x in sequence: 61 | print(x, end=' ') 62 | -------------------------------------------------------------------------------- /week5_dynamic_programming1/3_edit_distance/edit_distance.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import numpy as np 3 | import sys 4 | 5 | 6 | def edit_distance(s, t): 7 | temp = np.zeros(shape=(len(s) + 1, len(t) + 1), dtype=int) 8 | 9 | for i in range(len(s)+1): 10 | temp[i, 0] = i 11 | for i in range(len(t)+1): 12 | temp[0, i] = i 13 | 14 | for i in range(1, len(s) + 1): 15 | for j in range(1, len(t) + 1): 16 | if s[i - 1] == t[j - 1]: 17 | temp[i, j] = temp[i - 1, j - 1] 18 | else: 19 | temp[i, j] = 1 + min(temp[i - 1, j], temp[i - 1, j - 1], temp[i, j - 1]) 20 | 21 | return (temp[len(s), len(t)]) 22 | 23 | 24 | if __name__ == "__main__": 25 | input = sys.stdin.read() 26 | input = list(map(str, input.split('\n'))) 27 | # print(edit_distance(input(), input())) 28 | print(edit_distance(input[0], input[1])) 29 | -------------------------------------------------------------------------------- /week5_dynamic_programming1/4_longest_common_subsequence_of_two_sequences/lcs2.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | 3 | import numpy as np 4 | import sys 5 | 6 | 7 | def lcs2(a, b): 8 | temp = np.zeros(shape=(len(a) + 1, len(b) + 1), dtype=int) 9 | max = 0 10 | 11 | for i in range(1, len(a) + 1): 12 | for j in range(1, len(b) + 1): 13 | if a[i - 1] == b[j - 1]: 14 | temp[i, j] = 1 + temp[i - 1, j - 1] 15 | if max < temp[i, j]: 16 | max = temp[i, j] 17 | else: 18 | temp[i, j] = 0 19 | 20 | return max 21 | 22 | 23 | if __name__ == '__main__': 24 | input = sys.stdin.read() 25 | data = list(map(int, input.split())) 26 | 27 | n = data[0] 28 | data = data[1:] 29 | a = data[:n] 30 | 31 | data = data[n:] 32 | m = data[0] 33 | data = data[1:] 34 | b = data[:m] 35 | 36 | print(lcs2(a, b)) 37 | 38 | # print(lcs2("commo", "mmorpg")) 39 | -------------------------------------------------------------------------------- /week5_dynamic_programming1/5_longest_common_subsequence_of_three_sequences/lcs3.py: -------------------------------------------------------------------------------- 1 | #Uses python3 2 | 3 | import sys 4 | 5 | def lcs3(a, b, c): 6 | #write your code here 7 | return min(len(a), len(b), len(c)) 8 | 9 | if __name__ == '__main__': 10 | input = sys.stdin.read() 11 | data = list(map(int, input.split())) 12 | an = data[0] 13 | data = data[1:] 14 | a = data[:an] 15 | data = data[an:] 16 | bn = data[0] 17 | data = data[1:] 18 | b = data[:bn] 19 | data = data[bn:] 20 | cn = data[0] 21 | data = data[1:] 22 | c = data[:cn] 23 | print(lcs3(a, b, c)) 24 | -------------------------------------------------------------------------------- /week5_dynamic_programming1/week5_dynamic_programming1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmelnyk/Algorithmic-toolbox/4120c988a19803409c796839903ff5e0553d0d6b/week5_dynamic_programming1/week5_dynamic_programming1.pdf -------------------------------------------------------------------------------- /week6_dynamic_programming2/1_maximum_amount_of_gold/knapsack.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | 4 | import numpy as np 5 | 6 | 7 | def optimal_weight(W, w): 8 | # write your code here 9 | 10 | matrix = np.zeros(shape=(len(w), W + 1), dtype=int) 11 | 12 | for j in range(0, len(w)): 13 | for i in range(1, W + 1): 14 | if w[j] > i: 15 | matrix[j, i] = matrix[j - 1, i] 16 | else: 17 | matrix[j, i] = max(w[j] + matrix[j - 1, i - w[j]], matrix[j - 1, i]) 18 | return matrix[len(w) - 1, W] 19 | 20 | 21 | if __name__ == '__main__': 22 | input = sys.stdin.read() 23 | W, n, *w = list(map(int, input.split())) 24 | print(optimal_weight(W, w)) 25 | -------------------------------------------------------------------------------- /week6_dynamic_programming2/2_partitioning_souvenirs/partition3.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | import sys 3 | import itertools 4 | 5 | def partition3(A): 6 | for c in itertools.product(range(3), repeat=len(A)): 7 | sums = [None] * 3 8 | for i in range(3): 9 | sums[i] = sum(A[k] for k in range(len(A)) if c[k] == i) 10 | 11 | if sums[0] == sums[1] and sums[1] == sums[2]: 12 | return 1 13 | 14 | return 0 15 | 16 | if __name__ == '__main__': 17 | input = sys.stdin.read() 18 | n, *A = list(map(int, input.split())) 19 | print(partition3(A)) 20 | 21 | -------------------------------------------------------------------------------- /week6_dynamic_programming2/3_maximum_value_of_an_arithmetic_expression/placing_parentheses.py: -------------------------------------------------------------------------------- 1 | # Uses python3 2 | from math import inf 3 | 4 | import numpy as np 5 | 6 | 7 | def evalt(a, b, op): 8 | if op == '+': 9 | return a + b 10 | elif op == '-': 11 | return a - b 12 | elif op == '*': 13 | return a * b 14 | else: 15 | assert False 16 | 17 | 18 | def min_and_max(m, M, op, i, j): 19 | tmp_min = inf 20 | tmp_max = -inf 21 | 22 | for k in range(i, j): 23 | a = evalt(M[i][k], m[k + 1][j], op[k]) 24 | b = evalt(m[i][k], m[k + 1][j], op[k]) 25 | c = evalt(M[i][k], M[k + 1][j], op[k]) 26 | d = evalt(m[i][k], M[k + 1][j], op[k]) 27 | 28 | tmp_min = min(tmp_min, a, b, c, d) 29 | tmp_max = max(tmp_max, a, b, c, d) 30 | 31 | return (tmp_min, tmp_max) 32 | 33 | 34 | def get_maximum_value(dataset): 35 | op = dataset[1:len(dataset):2] 36 | d = dataset[0:len(dataset) + 1:2] 37 | n = len(d) 38 | m = np.zeros(shape=(n, n), dtype=int) 39 | M = np.zeros(shape=(n, n), dtype=int) 40 | for i in range(n): 41 | m[i][i] = int(d[i]) 42 | M[i][i] = int(d[i]) 43 | 44 | for s in range(1, n): 45 | for i in range(n - s): 46 | j = i + s 47 | m[i][j], M[i][j] = min_and_max(m, M, op, i, j) 48 | return M[0][n - 1] 49 | 50 | 51 | if __name__ == "__main__": 52 | print(get_maximum_value(input())) 53 | -------------------------------------------------------------------------------- /week6_dynamic_programming2/week6_dynamic_programming2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmelnyk/Algorithmic-toolbox/4120c988a19803409c796839903ff5e0553d0d6b/week6_dynamic_programming2/week6_dynamic_programming2.pdf --------------------------------------------------------------------------------