├── README.md ├── combinations_permutations ├── combinations.py ├── combinations_recursive.py └── permutation.py ├── divide_and_conquer └── fast_sequence_sum.py ├── dynamic-programming └── merge-files.md ├── etc_examples ├── anagram.py ├── baekjoon │ └── _01024_series_int.py ├── caesar_cipher.py ├── data ├── fibonacci.py ├── gcd.py ├── hanoi_tower.py ├── max_palindrome.py ├── multiply_integers.py ├── sieve_of_eratosthenes_bitmask.py ├── str_rotation.py ├── tsp.py └── xdecimal_number.py ├── graph ├── bfs.py ├── bfs_dfs.py ├── check_cycle.py ├── find_cut_vertex.py ├── graph │ ├── _base_graph.py │ ├── _list_graph.py │ └── _matrix_graph.py ├── graph_adjacency_list.py ├── graph_adjacency_matrix.py ├── shortest-path-algorithms │ ├── dijkstra.py │ └── floyd-warshall.py └── tarjan_scc.py ├── prime-number └── sieve_of_eratosthenes.py ├── problems_solving ├── algospot │ ├── allergy.py │ ├── asym_tiling.py │ ├── blockgame.py │ ├── boardcover1.py │ ├── boggle.py │ ├── brackets2.py │ ├── childrenday.py │ ├── christmas.py │ ├── clocksync.py │ ├── combinations_exhaust_search.py │ ├── data │ ├── dictionary.py │ ├── dragon.py │ ├── fence.py │ ├── firetrucks.py │ ├── fortress.py │ ├── gallery.py │ ├── genius.py │ ├── graduation.py │ ├── hanoi4.py │ ├── insertion.py │ ├── ites.py │ ├── jaehasafe.py │ ├── josephus.py │ ├── jumpgame.py │ ├── karatsuba_multiply.py │ ├── klis.py │ ├── kmp.py │ ├── longest_increasing_subsequence.py │ ├── lunchbox.py │ ├── matchorder.py │ ├── maxsum.py │ ├── minastirith.py │ ├── morse.py │ ├── naming.py │ ├── nthlon.py │ ├── numb3rs.py │ ├── numbergame.py │ ├── packing.py │ ├── palindromize.py │ ├── pass486.py │ ├── pi.py │ ├── picnic.py │ ├── polynomio.py │ ├── potion.py │ ├── quad_tree_reverse.py │ ├── quantize.py │ ├── restore.py │ ├── rock_festival.py │ ├── routing.py │ ├── runningmedian.py │ ├── snail.py │ ├── strjoin.py │ ├── sushi.py │ ├── test │ ├── tictactoe.py │ ├── tiling2.py │ ├── traversal.py │ ├── trianglepath.py │ ├── tripathcnt.py │ ├── tsp1.py │ ├── wildcard.py │ ├── wordchain.py │ └── zimbabwe.py ├── baekjoon │ ├── acm_craft.py │ ├── balanced_world.py │ ├── bertran_postulate.py │ ├── cardgame.py │ ├── dance_dance_revolution_2342.py │ ├── data │ ├── decreasing_number.py │ ├── evaluate_parenthesis.py │ ├── find_parent_in_tree.py │ ├── goldbach_conjecture.py │ ├── henry.py │ ├── lcs2.py │ ├── lightbulb.py │ ├── make_colored_paper.py │ ├── make_n_to_1.py │ ├── matrix_multiplication_order.py │ ├── merge_files.py │ ├── moving_units.py │ ├── multiplication.py │ ├── naval_battle.py │ ├── no_1021_circular_queue.py │ ├── no_10816_card_number2.py │ ├── no_10866_deck.py │ ├── no_11279_max_heap.py │ ├── no_11286_absolute_heap.py │ ├── no_11723_set.py │ ├── no_12015_length_of_lis.py │ ├── no_12852_change_it_to_1_2.py │ ├── no_1300_kth_number.py │ ├── no_15649_N_and_M_1.py │ ├── no_15650_N_and_M_2.py │ ├── no_15651_N_and_M_3.py │ ├── no_15652_N_and_M_4.py │ ├── no_1619_pick_out_points.py │ ├── no_1654_cutting_off_lan_wires.py │ ├── no_1655_tell_median.py │ ├── no_18258_queue_2.py │ ├── no_1920_binary_search.py │ ├── no_1927_min_heap.py │ ├── no_1966_printer_queue.py │ ├── no_2110_installing_routers.py │ ├── no_2164_card2.py │ ├── no_2805_chopping_woods.py │ ├── no_5430_AC.py │ ├── oreun_numbers.py │ ├── ox_quiz.py │ ├── padovan_sequence.py │ ├── police_car.py │ ├── queue.py │ ├── remote_controller.py │ ├── rgb.py │ ├── stack_sequence.py │ ├── trailing_zeros_binomial_coefficient.py │ ├── tree_traverse.py │ └── wire.py ├── kakao │ ├── 2020-blind-algorithm-test │ │ ├── q1_string_compression.py │ │ ├── q2_parenthesis_transformation.py │ │ ├── q3_lock_and_key.py │ │ ├── q4_lyrics_search.py │ │ ├── q6_check_outerwall.py │ │ └── q7_moving_drone.py │ ├── code_festival_2018 │ │ ├── data │ │ └── preliminary_1_bounty_hunter.py │ ├── filename_merge.py │ ├── kakao_1_1.py │ ├── kakao_1_2.py │ ├── kakao_1_3.py │ ├── kakao_1_4.py │ └── news_clustering.py ├── programmers │ └── number_to_124.py └── project-euler │ ├── data042 │ ├── names.txt │ ├── pro004_largest_palindrome.py │ ├── pro005_lcm.py │ ├── pro006_square_sum.py │ ├── pro007_nth_prime.py │ ├── pro008_largest_substring.py │ ├── pro009_pythagoras.py │ ├── pro010_prime_sum.py │ ├── pro011_max_multiple_grid.py │ ├── pro012_triangle_number.py │ ├── pro013_first10.py │ ├── pro014_max_collaz.py │ ├── pro015_path_to_lattice.py │ ├── pro016_sum_digit.py │ ├── pro017_length_of_digit.py │ ├── pro018_max_line_sum.py │ ├── pro019_monday.py │ ├── pro020_sum_digit2.py │ ├── pro021_familiar_number.py │ ├── pro022_name_value.py │ ├── pro023_abun_n_sum.py │ ├── pro024_lexicographic_sequence.py │ ├── pro025_fibo_d.py │ ├── pro026_longest_recurring_sequences.py │ ├── pro027_euler_equation.py │ ├── pro028_spiral_sums.py │ ├── pro029_all_squares.py │ ├── pro030_get_self_sum.py │ ├── pro031_combinate_2pounds.py │ ├── pro032_pandigital_sum.py │ ├── pro033_weird_reduction.py │ ├── pro034_sum_digits_factorial.py │ ├── pro035_circular_prime.py │ ├── pro036_sum_of_palindromes_in_base_10_and_2.py │ ├── pro037_prime_always.py │ ├── pro038_largest_pandigital_number.py │ ├── pro039_max_number_of_right_triangles.py │ ├── pro040_find_nth_digit.py │ ├── pro041_largest_prime_pandigital_number.py │ ├── pro042_triangular_number.py │ ├── pro043_sum_pandigital.py │ ├── pro044_pentagoanl_number.py │ ├── pro045_hexpentatrigonal_number.py │ ├── pro046_composite_conjecture.py │ ├── pro047_same_count_factors_numbers.py │ ├── pro048_last_ten_digits.py │ ├── pro049_anagram_arithmetical_progression.py │ └── pro050_longest_prime_sum_prime.py ├── search-algorithm └── binary_search.py ├── simple_data_structure ├── linked_list.py ├── queue.py └── stack.py ├── sorting ├── bubble_sort.py ├── insertion_sort.py ├── merge_sort.py ├── quick_sort.py ├── radix_sort.py ├── selection_sort.py ├── shell_sort.py └── sort_functions.py ├── str └── trie.py └── tree ├── binary_tree.py └── treap.py /combinations_permutations/combinations.py: -------------------------------------------------------------------------------- 1 | """Combinations without replacements in Python 2 | 3 | 4 | Source referred in Python org. 5 | Last Modified Date: 2018/12/30 6 | """ 7 | def combination(arr, r): 8 | arr = sorted(arr) 9 | used = [0 for _ in range(len(arr))] 10 | 11 | def generate(chosen): 12 | if len(chosen) == r: 13 | print(chosen) 14 | return 15 | 16 | start = arr.index(chosen[-1]) + 1 if chosen else 0 17 | for nxt in range(start, len(arr)): 18 | if used[nxt] == 0 and (nxt == 0 or arr[nxt-1] != arr[nxt] or used[nxt-1]): 19 | chosen.append(arr[nxt]) 20 | used[nxt] = 1 21 | generate(chosen) 22 | chosen.pop() 23 | used[nxt] = 0 24 | generate([]) 25 | 26 | -------------------------------------------------------------------------------- /combinations_permutations/combinations_recursive.py: -------------------------------------------------------------------------------- 1 | """Get combination of series in recursive way""" 2 | 3 | 4 | def combinations(n, to_pick, picked=[]): 5 | if to_pick == 0: 6 | print(picked) 7 | return 8 | smallest = 0 if not picked else picked[-1] + 1 9 | for nxt in range(smallest, n): 10 | picked.append(nxt) 11 | combinations(n, to_pick-1, picked) 12 | picked.pop() 13 | 14 | 15 | combinations(10, 3) 16 | -------------------------------------------------------------------------------- /combinations_permutations/permutation.py: -------------------------------------------------------------------------------- 1 | """Implement permutation in Python""" 2 | 3 | 4 | def permutation(arr, r): 5 | arr = sorted(arr) 6 | used = [0 for _ in range(len(arr))] 7 | 8 | def generate(chosen, used): 9 | if len(chosen) == r: 10 | print(chosen) 11 | return 12 | 13 | for i in range(len(arr)): 14 | if not used[i] and (i == 0 or arr[i-1] != arr[i] or used[i-1]): 15 | chosen.append(arr[i]) 16 | used[i] = 1 17 | generate(chosen, used) 18 | used[i] = 0 19 | chosen.pop() 20 | generate([], used) 21 | -------------------------------------------------------------------------------- /divide_and_conquer/fast_sequence_sum.py: -------------------------------------------------------------------------------- 1 | """Get the sum of sequences between 1 to given natural number n. 2 | 3 | I will all input is natural number over 0. 4 | """ 5 | 6 | 7 | def fast_sum(n): 8 | 9 | if n == 1: 10 | return 1 11 | elif n % 2 == 1: 12 | return fast_sum(n-1) + n 13 | else: 14 | return n*n // 4 + fast_sum(n//2) 15 | -------------------------------------------------------------------------------- /etc_examples/anagram.py: -------------------------------------------------------------------------------- 1 | """Check if two arguments are anagrams 2 | 3 | This algorithm is implement in time complexity O(n). 4 | 5 | Start Date: 2018/04/11 6 | End Date: 2018/04/11 7 | """ 8 | from string import ascii_letters as alphabets 9 | 10 | 11 | def is_anagram(a, b): 12 | """Check if two arguments are anagrams 13 | 14 | :input: 15 | a : STR 16 | b : STR 17 | :return: 18 | True if two are anagrams otherwise False 19 | """ 20 | if len(a) != len(b): 21 | return False 22 | check = [0 for _ in range(len(alphabets))] 23 | 24 | for i in range(len(a)): 25 | check[ alphabets.index(a[i]) ] += 1 26 | check[ alphabets.index(b[i]) ] -= 1 27 | 28 | return True if all(c == 0 for c in check) else False 29 | -------------------------------------------------------------------------------- /etc_examples/baekjoon/_01024_series_int.py: -------------------------------------------------------------------------------- 1 | """ 2 | N과 L이 주어질 때, 합이 N이면서, 길이가 적어도 L이면서 가장 짧은 연속된 음이 아닌 정수 리스트를 3 | 구하는 프로그램을 작성하시오. 4 | 5 | 만약 리스트의 길이가 100보다 작거나 같으면, 연속된 수를 첫째 줄에 공백으로 구분하여 출력한다. 만약 6 | 길이가 100보다 크거나 그러한 수열이 없을 때는 -1을 출력한다. 7 | """ 8 | def gcd(a, b): 9 | return a if b == 0 else gcd(b, a % b) 10 | 11 | 12 | def int_series(n, l): 13 | series = [] 14 | if n % l == 0 and l % 2 == 1: 15 | series = [n // l] * l 16 | mid = len(series) // 2 17 | for i in range(1, mid+1): 18 | series[mid-i] -= i 19 | series[mid+i] += i 20 | elif l % 2 == 0 and l // gcd(n, l) == 2: 21 | series = [n / l] * l 22 | mid = len(series) // 2 23 | for i in range(mid): 24 | series[mid+i] += (i+0.5) 25 | series[mid-i-1] -= (0.5+i) 26 | series = [int(n) for n in series] 27 | return series if all(n >= 0 for n in series) else 0 28 | 29 | 30 | if __name__ == '__main__': 31 | n, l = (int(n) for n in input().split()) 32 | exists = False 33 | 34 | 35 | while l <= 100: 36 | series = int_series(n, l) 37 | if series: 38 | exists = True 39 | break 40 | else: 41 | l += 1 42 | 43 | 44 | if exists: 45 | answer = '' 46 | for n in series: 47 | answer += str(n) + ' ' 48 | print(answer.rstrip()) 49 | else: 50 | print(-1) 51 | -------------------------------------------------------------------------------- /etc_examples/caesar_cipher.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | LOWER = string.ascii_lowercase 4 | SKIP = string.digits + string.whitespace + string.punctuation 5 | 6 | 7 | def caesar_cipher_encode(plain_text: str, step=3): 8 | cipher = '' 9 | 10 | for c in plain_text: 11 | if c in SKIP: 12 | cipher += c 13 | continue 14 | diff = ord(c) - (ord('a') if c in LOWER else ord('A')) 15 | diff = (diff + step) % 26 16 | cipher += chr(diff + 17 | (ord('a') if c in LOWER else ord('A')) 18 | ) 19 | return cipher 20 | 21 | 22 | def caesar_cipher_decode(cipher: str, step=3): 23 | return caesar_cipher_encode(cipher, -step) 24 | -------------------------------------------------------------------------------- /etc_examples/data: -------------------------------------------------------------------------------- 1 | 2 2 | 3 3 | 0.0000000000 611.6157225201 648.7500617289 4 | 611.6157225201 0.0000000000 743.8557967501 5 | 648.7500617289 743.8557967501 0.0000000000 6 | 4 7 | 0.0000000000 326.0008994586 503.1066076077 290.0250922998 8 | 326.0008994586 0.0000000000 225.1785728436 395.4019367384 9 | 503.1066076077 225.1785728436 0.0000000000 620.3945520632 10 | 290.0250922998 395.4019367384 620.3945520632 0.0000000000 11 | -------------------------------------------------------------------------------- /etc_examples/gcd.py: -------------------------------------------------------------------------------- 1 | """Euclidean algorithm of 2 integers 2 | 3 | 4 | Date : 2018/03/30 5 | """ 6 | 7 | 8 | def gcd(a, b): 9 | return a if b == 0 else gcd(b, a % b) 10 | -------------------------------------------------------------------------------- /etc_examples/hanoi_tower.py: -------------------------------------------------------------------------------- 1 | """Hanoi tower algorithm in Python 2 | 3 | In computer programming, hanoi tower problem is very famous. 4 | Let's get it done with Python 5 | 6 | Date: 2018/03/14 7 | """ 8 | 9 | _MOVE_COUNT = 0 10 | 11 | 12 | def hanoi(n): 13 | """Hanoi tower algorithm in Python 14 | 15 | This gets only one argument named 'n', which indicates a number of disks. 16 | It should be an integer over 0. 17 | 18 | It traces disks' movement and print it one by one. 19 | and last prints its total count of movement. 20 | """ 21 | if not isinstance(n, int) or n <= 0: 22 | raise Exception("n should be an interger over 0") 23 | 24 | global _MOVE_COUNT 25 | 26 | def move(n, start, to): 27 | """Move one single disk from given start to dest point 28 | 29 | You know our disks are numbered as 1, 2, 3. 30 | so you can guess '6-start-to' is the remainder disk from start and dest disk 31 | """ 32 | global _MOVE_COUNT 33 | 34 | if n == 0: 35 | return 36 | move(n-1, start, 6-start-to) 37 | print(f'{start} -> {to}') 38 | _MOVE_COUNT += 1 39 | move(n-1, 6-start-to, to) 40 | 41 | print(f"\nNumber of disks are {n}\n") 42 | move(n, 1, 3) 43 | print(f"\nTotal movement counts are {_MOVE_COUNT}") 44 | _MOVE_COUNT = 0 45 | -------------------------------------------------------------------------------- /etc_examples/max_palindrome.py: -------------------------------------------------------------------------------- 1 | """Get the longest palindrome in a given string""" 2 | 3 | 4 | def longest_palindrome(s: str) -> str: 5 | if not s: 6 | return 0 7 | 8 | N = len(s) 9 | cache = [[-1 for _ in range(N)] for _ in range(N)] 10 | ans = [] 11 | 12 | def all_same(lo, hi): 13 | first = s[lo] 14 | for i in range(lo+1, hi+1): 15 | if s[i] != first: 16 | return False 17 | return True 18 | 19 | def get_len(lo, hi): 20 | if cache[lo][hi] != -1: 21 | return cache[lo][hi] 22 | elif lo == hi: 23 | return 1 24 | 25 | # first part 26 | add = lo 27 | if get_len(lo+1, hi) == hi - (lo+1) + 1 and all_same(lo+1, hi) and s[add] == s[lo+1]: 28 | pre_ret = get_len(lo+1, hi) + 1 29 | elif s[add] == s[hi] and get_len(lo+1, hi-1) == (hi-1) - (lo+1) + 1: 30 | pre_ret = get_len(lo+1, hi-1) + 2 31 | else: 32 | pre_ret = get_len(lo+1, hi) 33 | 34 | 35 | # latter part 36 | add = hi 37 | if get_len(lo, hi-1) == hi-1 - lo + 1 and all_same(lo, hi-1) and s[add] == s[hi-1]: 38 | suf_ret = get_len(lo, hi-1) + 1 39 | elif s[add] == s[lo] and get_len(lo+1, hi-1) == (hi-1) - (lo+1) + 1: 40 | suf_ret = get_len(lo+1, hi-1) + 2 41 | else: 42 | suf_ret = get_len(lo, hi-1) 43 | 44 | cache[lo][hi] = max(pre_ret, suf_ret) 45 | return cache[lo][hi] 46 | 47 | def longest_one(): 48 | max_len = get_len(0, N-1) 49 | for h in range(N): 50 | for t in range(h, N): 51 | if get_len(h, t) == max_len and t - h + 1 == max_len: 52 | ans.append(s[h:t+1]) 53 | 54 | return ans 55 | 56 | return longest_one() 57 | -------------------------------------------------------------------------------- /etc_examples/multiply_integers.py: -------------------------------------------------------------------------------- 1 | """Multiply integers as we used to do in schools. 2 | 3 | Time complexity is O(n ** 2) 4 | """ 5 | def multiply_integers(a: int, b: int): 6 | 7 | def process(a): 8 | if isinstance(a, int) and isinstance(b, int): 9 | a = [int(n) for n in reversed(str(a))] 10 | elif isinstance(a, list) and isinstance(b, list): 11 | a = int(''.join(reversed([str(c) for c in a]))) 12 | else: 13 | raise TypeError("Two elements should be all integers or lists") 14 | return a 15 | 16 | 17 | def normalize(nums: list): 18 | nums.append(0) 19 | 20 | for i in range(len(nums)-1): 21 | if nums[i] < 0: 22 | borrow = (abs(nums[i]) + 9) // 10 23 | nums[i+1] -= borrow 24 | nums[i] += borrow * 10 25 | else: 26 | nums[i+1] += nums[i] // 10 27 | nums[i] %= 10 28 | 29 | while len(nums) > 1 and nums[-1] == 0: 30 | nums.pop() 31 | 32 | return nums 33 | 34 | 35 | def multiply(a: list, b: list): 36 | ans = [0 for _ in range(len(a) + len(b) + 1)] 37 | for i in range(len(a)): 38 | for j in range(len(b)): 39 | ans[i+j] += a[i] * b[j] 40 | 41 | return ans 42 | 43 | a = process(a) 44 | b = process(b) 45 | 46 | ans = multiply(a, b) 47 | ans = normalize(ans) 48 | ans = process(ans) 49 | 50 | return ans 51 | 52 | 53 | 54 | if __name__ == '__main__': 55 | assert multiply_integers(1234, 5678) == 7006652 56 | -------------------------------------------------------------------------------- /etc_examples/sieve_of_eratosthenes_bitmask.py: -------------------------------------------------------------------------------- 1 | """Implement sieve of Eratosthenes in BITMASK version 2 | 3 | OMG... There are so many geeks around the world. 4 | When the size of the sieve is too big like over billion, 5 | then you can consider making a sieve with bitmask. 6 | 7 | So let's get down to code directly... 8 | """ 9 | SIZE = 2 ** 16 + 1 # Size is too big... Isn't it? 10 | 11 | 12 | class Sieve: 13 | def __init__(self, size): 14 | self._size = size 15 | self._sieve = [255 for _ in range(SIZE // 8 + 1)] 16 | 17 | self._set_composite(0) 18 | self._set_composite(1) 19 | 20 | for i in range(2, int(self._size ** (1/2))+1): 21 | for j in range(i*i, self._size+1, i): 22 | self._set_composite(j) 23 | print(f"Sieve of size {size} is initialized") 24 | 25 | def is_prime(self, n): 26 | if n > self._size: 27 | raise ValueError(f"This sieve only support integers equal to or less than {self._size}") 28 | return True if self._sieve[n >> 3] & (1 << (n & 7)) else False 29 | 30 | def _set_composite(self, n): 31 | self._sieve[n >> 3] &= ~(1 << (n & 7)) 32 | 33 | 34 | SIZE = 2 ** 16 35 | SIZE_SQRT = int(SIZE ** (1/2)) 36 | sieve = [1 for _ in range(SIZE+1)] 37 | sieve[0] = sieve[1] = 0 38 | TEST = 20 39 | 40 | for i in range(2, SIZE_SQRT+1): 41 | if sieve[i] == 1: 42 | for j in range(i*i, SIZE+1, i): 43 | sieve[j] = 0 44 | 45 | for i in range(2, TEST+1): 46 | print(f"{i:>3} : {'prime' if sieve[i] else 'composite'}") 47 | 48 | -------------------------------------------------------------------------------- /etc_examples/xdecimal_number.py: -------------------------------------------------------------------------------- 1 | """Change given number to target decimal number algorithm 2 | 3 | Start Date : 2017/12/24 4 | End Date : 2017/12/24 5 | """ 6 | 7 | 8 | def xdecimal_number(number, x_dec=2): 9 | """Return x_dec decimal number with given 10 decimal number 10 | 11 | :input: 12 | number: Wanted 10 decimal number. Should be an int over -1. 13 | x_dec: Target decimal. Must be an int over 1. Defaults to 2. 14 | :return: 15 | str. x_dec decimal number. 16 | """ 17 | # Input validation 18 | if not isinstance(number, int) or number <= -1: 19 | raise ValueError("number must be an integer over -1") 20 | if not isinstance(x_dec, int) or number <= 1: 21 | raise ValueError("x_dec must be an integer over 1") 22 | 23 | e = 1 24 | answer = '' 25 | while number >= x_dec ** e: 26 | e += 1 27 | e -= 1 28 | 29 | for _ in range(e, -1, -1): 30 | quotient = number // x_dec ** e 31 | number -= quotient * x_dec ** e 32 | answer += str(quotient) 33 | e -= 1 34 | 35 | return answer 36 | -------------------------------------------------------------------------------- /graph/bfs.py: -------------------------------------------------------------------------------- 1 | def shortest_path(g, a, b): 2 | N = len(g) 3 | parent = [-1] * N 4 | parent[a] = a 5 | distance = [-1] * N 6 | distance[a] = 0 7 | path = [b] 8 | 9 | q = [a] 10 | while q: 11 | here = q.pop(0) 12 | for there in range(N): 13 | if g[here][there] and distance[there] == -1: 14 | q.append(there) 15 | distance[there] = distance[here] + 1 16 | parent[there] = here 17 | 18 | while parent[b] != b: 19 | b = parent[b] 20 | path.append(b) 21 | 22 | path.reverse() 23 | return path 24 | 25 | 26 | def bfs(g, start): 27 | N = len(g) 28 | discovered = [0] * N 29 | q = [start] 30 | discovered[start] = 1 31 | 32 | while q: 33 | now = q.pop(0) 34 | print(now) 35 | for i in range(N): 36 | if g[now][i] and not discovered[i]: 37 | q.append(i) 38 | discovered[i] = 1 39 | 40 | 41 | def connect(a, b, g): 42 | g[a][b] = 1 43 | g[b][a] = 1 44 | 45 | 46 | if __name__ == '__main__': 47 | N = 9 48 | g = [[0] * N for _ in range(N)] 49 | connect(0, 1, g) 50 | connect(0, 4, g) 51 | connect(0, 3, g) 52 | connect(0, 7, g) 53 | connect(5, 4, g) 54 | connect(1, 2, g) 55 | connect(1, 3, g) 56 | connect(2, 5, g) 57 | connect(2, 6, g) 58 | connect(3, 6, g) 59 | connect(8, 6, g) 60 | 61 | print(shortest_path(g, 0, 6)) 62 | -------------------------------------------------------------------------------- /graph/bfs_dfs.py: -------------------------------------------------------------------------------- 1 | """Implement DFS and BFS in Python""" 2 | from graph_adjacency_list import list_undirected_weight 3 | from graph_adjacency_matrix import matrix_undirected_weight 4 | 5 | 6 | # DFS 1. Recursive way 7 | def dfs_recursive(graph, x): 8 | _check = [0 for _ in range(graph.vector_n+1)] 9 | _check[x] = 1 10 | print(x) 11 | 12 | def _recursive(graph, x): 13 | for i in range(1, graph.vector_n+1): 14 | if graph.matrix[x][i] == 1 and _check[i] == 0: 15 | print(i) 16 | _check[i] = 1 17 | _recursive(graph, i) 18 | 19 | _recursive(graph, x) 20 | 21 | 22 | # DFS 2. Stack way 23 | def dfs_stack(graph, x): 24 | _check = [0 for _ in range(graph.vector_n+1)] 25 | stack = [] 26 | _check[x] = 1 27 | stack.append(x) 28 | print(x) 29 | 30 | while stack: 31 | n = stack[-1] 32 | for i in range(1, graph.vector_n+1): 33 | found = False 34 | if graph.matrix[n][i] == 1 and _check[i] == 0: 35 | print(i) 36 | _check[i] = 1 37 | stack.append(i) 38 | found = True 39 | break 40 | if not found: 41 | stack.pop() 42 | 43 | 44 | # BFS 45 | def bfs(graph, x): 46 | check[x] = 1 47 | queue.append(x) 48 | print(x) 49 | 50 | while queue: 51 | y = queue.pop(0) 52 | for i in range(1, graph.vector_n+1): 53 | if graph.matrix[y][i] == 1 and check[i] == 0: 54 | check[i] = 1 55 | queue.append(i) 56 | print(i) 57 | 58 | 59 | if __name__ == '__main__': 60 | 61 | g = matrix_undirected_weight(5) 62 | g.add_edge(1, 5) 63 | g.add_edge(1, 2) 64 | g.add_edge(2, 3) 65 | g.add_edge(2, 5) 66 | g.add_edge(3, 4) 67 | 68 | 69 | queue = [] 70 | dfs_recursive(g, 1) 71 | print() 72 | dfs_stack(g, 1) 73 | print() 74 | check = [0 for _ in range(1000)] 75 | bfs(g, 1) 76 | -------------------------------------------------------------------------------- /graph/graph/_base_graph.py: -------------------------------------------------------------------------------- 1 | class _BaseGraph: 2 | def __init__(self, n, name='graph', weight=1, directed=False): 3 | self.n_vector = n 4 | self.n_edge = 0 5 | self.name = name 6 | self.weight = weight 7 | self.directed = directed 8 | self.name_set = False 9 | 10 | def add_edge(self, src, dest, weight=1): 11 | raise NotImplementedError("Not implemented boy...") 12 | 13 | def edge_exists(self, src, dest): 14 | raise NotImplementedError("Not implemented boy...") 15 | 16 | def set_vector_names(self): 17 | """Later we'll assume vectors have names""" 18 | raise NotImplementedError("Not implemented boy...") 19 | 20 | def show_graph(self): 21 | for i in range(1, self.n_vector+1): 22 | print(f'{i} is connected to {self.graph[i]}') 23 | 24 | def vector_exists(self, src): 25 | return True if src <= self.n_vector + 1 else False 26 | 27 | def __repr__(self): 28 | return "Graph named '" + self.name + "'" 29 | -------------------------------------------------------------------------------- /graph/graph/_list_graph.py: -------------------------------------------------------------------------------- 1 | from _base_graph import _BaseGraph 2 | 3 | 4 | class _ListGraph(_BaseGraph): 5 | def __init__(self, n, name='List graph'): 6 | super().__init__(n, name) 7 | self.graph = [[] for _ in range(n+1)] 8 | 9 | def add_edge(self, src, dest, weight=1): 10 | if not self.edge_exists(src, dest): 11 | self.n_edge += 1 12 | self.graph[src].append((dest, weight)) 13 | else: 14 | for i, tup in enumerate(self.graph[src]): 15 | if dest == tup[0]: 16 | self.graph[src][i] = (dest, weight) 17 | 18 | if not self.directed: 19 | if not self.edge_exists(dest, src): 20 | self.n_edge += 1 21 | self.graph[dest].append((src, weight)) 22 | else: 23 | for i, tup in enumerate(self.graph[dest]): 24 | if src == tup[0]: 25 | self.graph[dest][i] = (src, weight) 26 | 27 | def edge_exists(self, src, dest): 28 | for v, w in self.graph[src]: 29 | if dest == v: 30 | return True 31 | return False 32 | -------------------------------------------------------------------------------- /graph/graph/_matrix_graph.py: -------------------------------------------------------------------------------- 1 | from _base_graph import _BaseGraph 2 | 3 | 4 | class _MatrixGraph(_BaseGraph): 5 | def __init__(self, n, name='Matrix graph'): 6 | super().__init__(n, name) 7 | self.graph = [[0 for _ in range(self.n_vector+1)] for _ in range(self.n_vector+1)] 8 | 9 | def add_edge(self, src, dest, weight=1): 10 | # 1 directed vs undirected 11 | 12 | if not self.graph[src][dest]: 13 | self.n_edge += 1 14 | self.graph[src][dest] = weight 15 | 16 | if not self.directed: 17 | if not self.graph[dest][src]: 18 | self.n_edge += 1 19 | self.graph[dest][src] = weight 20 | 21 | def edge_exists(self, src, dest): 22 | return True if self.graph[src][dest] else False 23 | -------------------------------------------------------------------------------- /graph/graph_adjacency_list.py: -------------------------------------------------------------------------------- 1 | """Implement graph in an adjacency matrix form 2 | 3 | 4 | There are two ways to implement graph. 5 | One is 'adjacency matrix' form. 6 | 7 | This implementation has some pros and cons. 8 | 9 | Pros: 10 | 1. Easy to implement 11 | 12 | Cons: 13 | 1. If Edges are sparse, too much spaces are wasted. 14 | In a matrix form, space takes of V**2. But even if you assume the graph 15 | is a complete graph, number of edges are (v-1)(v-2) / 2. 16 | 17 | Now, I'm gonna make it. 18 | 19 | Date : 2018/09/05 20 | """ 21 | class list_undirected_weight: 22 | """Graph in an adjacency list form 23 | 24 | Vertex number starts from '1' 25 | """ 26 | def __init__(self, n): 27 | self.matrix = [[] for _ in range(n+1)] 28 | self.vector_n = len(self.matrix) 29 | 30 | def add_edge(self, src, dest, weight=1): 31 | self.matrix[src].append((dest, weight)) 32 | self.matrix[dest].append((src, weight)) 33 | -------------------------------------------------------------------------------- /graph/graph_adjacency_matrix.py: -------------------------------------------------------------------------------- 1 | """Implement graph in an adjacency matrix form 2 | 3 | 4 | There are two ways to implement graph. 5 | One is 'adjacency matrix' form. 6 | 7 | This implementation has some pros and cons. 8 | 9 | Pros: 10 | 1. Easy to implement 11 | 12 | Cons: 13 | 1. If Edges are sparse, too much spaces are wasted. 14 | In a matrix form, space takes of V**2. But even if you assume the graph 15 | is a complete graph, number of edges are (v-1)(v-2) / 2. 16 | 17 | Now, I'm gonna make it. 18 | 19 | Date : 2018/09/05 20 | """ 21 | class matrix_undirected_weight: 22 | """Graph in an adjacency matrix form 23 | 24 | Vertex number starts from '1' 25 | """ 26 | def __init__(self, n): 27 | self.matrix = [[0 for _ in range(n+1)] for _ in range(n+1)] 28 | self.vector_n = n 29 | 30 | 31 | def add_edge(self, src, dest, weight=1): 32 | self.matrix[src][dest] = weight 33 | self.matrix[dest][src] = weight 34 | 35 | 36 | -------------------------------------------------------------------------------- /graph/shortest-path-algorithms/dijkstra.py: -------------------------------------------------------------------------------- 1 | from heapq import heappop, heappush 2 | # Python's heapq is min-queue, unlike C++ priority_queue data structure 3 | from math import inf 4 | 5 | 6 | # Connect two vetcies in a graph with value 'v'. Undirected is default. 7 | def connnect(graph, a, b, v, directed=False): 8 | graph[a][b] = v 9 | if not directed: 10 | graph[b][a] = v 11 | 12 | 13 | def dijkstra(src, graph): 14 | # we suppose graph is matrix-based. 15 | N = len(graph) 16 | dist = [inf] * N 17 | dist[src] = 0 18 | pq = [(0, src)] # pq is a priority queue of (cost, vertex) tuples 19 | 20 | while pq: 21 | cost, here = heappop(pq) 22 | if dist[here] < cost: 23 | continue 24 | 25 | for there in range(N): 26 | if graph[here][there] != -1: # We suppose '-1' means 'not connected' here. 27 | next_dist = cost + graph[here][there] 28 | if dist[there] > next_dist: 29 | dist[there] = next_dist 30 | heappush(pq, (next_dist, there)) 31 | return dist 32 | 33 | 34 | if __name__ == '__main__': 35 | # test set 1 36 | graph1 = [[-1] * 4 for _ in range(4)] 37 | connnect(graph1, 0, 1, 2) 38 | connnect(graph1, 0, 2, 12) 39 | connnect(graph1, 1, 3, 4) 40 | connnect(graph1, 2, 3, 3) 41 | 42 | # test set 2 43 | graph2 = [[-1] * 7 for _ in range(7)] 44 | connnect(graph2, 0, 1, 5) 45 | connnect(graph2, 0, 2, 1) 46 | connnect(graph2, 2, 3, 2) 47 | connnect(graph2, 1, 3, 1) 48 | connnect(graph2, 3, 4, 5) 49 | connnect(graph2, 1, 5, 3) 50 | connnect(graph2, 1, 6, 3) 51 | connnect(graph2, 5, 6, 2) 52 | connnect(graph2, 3, 5, 3) 53 | 54 | 55 | test_set = [graph1, graph2] 56 | for i, g in enumerate(test_set): 57 | print('\n' + '-' * 30) 58 | print('Test', i+1, '/', len(test_set)) 59 | print(dijkstra(0, g)) 60 | -------------------------------------------------------------------------------- /graph/tarjan_scc.py: -------------------------------------------------------------------------------- 1 | """Implement Tarjan's SCC condensation algorithm in DIRECTED graph""" 2 | 3 | N = 10 4 | graph = [[0] * N for _ in range(N)] 5 | scc_ids = [-1] * N 6 | discovered = [-1] * N 7 | stack = [] 8 | 9 | scc_counter = 0 10 | vertex_counter = 0 11 | 12 | 13 | def scc(here): 14 | ret = discovered[here] = vertex_counter 15 | vertex_counter += 1 16 | stack.append(here) 17 | 18 | for there in range(N): 19 | if graph[here][there] and discovered[there] == -1: 20 | ret = min(ret, scc(there)) 21 | elif graph[here][there] and scc_id[there] == -1: 22 | ret = min(ret, discovered[there]) 23 | 24 | if ret == discovered[here]: 25 | while True: 26 | t = stack.pop() 27 | scc_id[t] = scc_counter 28 | if t == here: 29 | break 30 | scc_counter += 1 31 | 32 | return ret 33 | 34 | 35 | def tarjan_scc(): 36 | for i in range(N): 37 | if not discovered[i] == -1: 38 | scc(i) 39 | 40 | return scc_id 41 | -------------------------------------------------------------------------------- /prime-number/sieve_of_eratosthenes.py: -------------------------------------------------------------------------------- 1 | """Sieve of Eratosthenes algorithm in Python 2 | 3 | This code implements sieve of eratosthenes algorithm. 4 | It returns prime numbers from 2 to n. 5 | I didn't put input validation code for minimalism. 6 | 7 | 8 | 2017/12/28 9 | """ 10 | 11 | 12 | def eratosthenes(n): 13 | checked = [1 for _ in range(n+1)] 14 | 15 | for i in range(2, n+1): 16 | if checked[i]: 17 | count = 2 18 | while i * count <= n: 19 | checked[i * count] = 0 20 | count += 1 21 | 22 | return [i for i in range(2, n+1) if checked[i]] 23 | 24 | 25 | if __name__ == '__main__': 26 | eratosthenes(100) 27 | -------------------------------------------------------------------------------- /problems_solving/algospot/allergy.py: -------------------------------------------------------------------------------- 1 | """Return minimum number of foods to satisfy all friends 2 | 3 | url: https://algospot.com/judge/problem/read/ALLERGY 4 | ID : ALLERGY 5 | """ 6 | def minimum_foods(eaters, FRIEND): 7 | FOOD = len(eaters) 8 | best = float('inf') 9 | edible = [0] * FRIEND 10 | can_eat = [[] for _ in range(FRIEND)] 11 | 12 | for i in range(len(eaters)): 13 | for f in eaters[i]: 14 | can_eat[f].append(i) 15 | 16 | 17 | def search(edible, chosen): 18 | nonlocal best 19 | if chosen >= best: 20 | return 21 | 22 | first = 0 23 | 24 | while first < FRIEND and edible[first] > 0: 25 | first += 1 26 | 27 | if first == FRIEND: 28 | best = chosen 29 | return 30 | 31 | for food in can_eat[first]: 32 | for j in eaters[food]: 33 | edible[j] += 1 34 | 35 | search(edible, chosen+1) 36 | 37 | for j in eaters[food]: 38 | edible[j] -= 1 39 | 40 | search(edible, 0) 41 | return best 42 | 43 | 44 | if __name__ == '__main__': 45 | T = int(input()) 46 | ans = [] 47 | 48 | for _ in range(T): 49 | FRIEND, MEAL = (int(n) for n in input().strip().split()) 50 | friends = list(input().strip().split()) 51 | eaters = [list() for _ in range(MEAL)] 52 | 53 | for food in eaters: 54 | satisfies = list(input().strip().split())[1:] 55 | for f in satisfies: 56 | food.append(friends.index(f)) 57 | 58 | ans.append(minimum_foods(eaters, FRIEND)) 59 | 60 | for n in ans: 61 | print(n) 62 | -------------------------------------------------------------------------------- /problems_solving/algospot/asym_tiling.py: -------------------------------------------------------------------------------- 1 | """Get ways to cover the board which is asymmetric from left to right 2 | 3 | :input: 4 | 3 5 | 2 6 | 4 7 | 92 8 | 9 | :return: 10 | 0 11 | 2 12 | 913227494 13 | """ 14 | MAX_T = 100 15 | MOD = 1000000007 16 | cache = [0 for _ in range(MAX_T+1)] 17 | cache[0] = 1 18 | cache[1] = 1 19 | cache[2] = 2 20 | 21 | 22 | for i in range(3, MAX_T+1): 23 | cache[i] = (cache[i-1] + cache[i-2]) % MOD 24 | 25 | def asym_tile(n): 26 | if n % 2 == 1: 27 | ans = (cache[n] - cache[n//2] + MOD) % MOD 28 | else: 29 | ans = (cache[n] - cache[n//2] - cache[n//2 - 1] + MOD) % MOD 30 | 31 | return ans 32 | 33 | 34 | if __name__ == '__main__': 35 | ans = [] 36 | C = int(input()) 37 | for _ in range(C): 38 | ans.append( asym_tile(int(input()))) 39 | 40 | for n in ans: 41 | print(n) 42 | -------------------------------------------------------------------------------- /problems_solving/algospot/boggle.py: -------------------------------------------------------------------------------- 1 | """Solve Boggle problem in algospot 2 | 3 | :input: 4 | 1 5 | URLPM 6 | XPRET 7 | GIAET 8 | XTNZY 9 | XOQRS 10 | 6 11 | PRETTY 12 | GIRL 13 | REPEAT 14 | KARA 15 | PANDORA 16 | GIAZAPX 17 | 18 | :return: 19 | PRETTY YES 20 | GIRL YES 21 | REPEAT YES 22 | KARA NO 23 | PANDORA NO 24 | GIAZAPX YES 25 | 26 | 27 | url: https://algospot.com/judge/problem/read/BOGGLE 28 | ID : BOGGLE 29 | """ 30 | SIZE = 5 31 | MOVES = [(x, y) for x in range(-1, 2) for y in range(-1, 2) if not (x == 0 and y == 0)] 32 | 33 | def board_to_int(board): 34 | ret = 0 35 | size = len(board) 36 | for x in range(size): 37 | for y in range(size): 38 | ret *= size 39 | ret += board[x][y] 40 | return ret 41 | 42 | 43 | def has_word(board, word): 44 | global cache, MOVES, SIZE 45 | 46 | 47 | 48 | 49 | if __name__ == '__main__': 50 | C = int(input()) 51 | ans = [] 52 | 53 | for _ in range(C): 54 | board = [] 55 | for _ in range(SIZE): 56 | board.append(input()) 57 | cache = [[[-1 for _ in range(26)] for _ in range(SIZE)] for _ in range(SIZE)] 58 | N = int(input()) 59 | for _ in range(N): 60 | word = input() 61 | # ans.append(word + (' YES' if has_word(board, word) else ' NO')) 62 | ans.append(word + (' YES' if has_word(board) else ' NO')) 63 | 64 | for n in ans: 65 | print(n) 66 | -------------------------------------------------------------------------------- /problems_solving/algospot/brackets2.py: -------------------------------------------------------------------------------- 1 | """Return if brackets match correctly or not 2 | 3 | :input 4 | 3 5 | ()() 6 | ({[}]) 7 | ({}[(){}]) 8 | 9 | :return: 10 | YES 11 | NO 12 | YES 13 | 14 | url : https://algospot.com/judge/problem/read/BRACKETS2 15 | ID : BRACKETS2 16 | """ 17 | OPENS = ['(', '{', '['] 18 | CLOSES = [')', '}', ']'] 19 | 20 | 21 | class Stack: 22 | def __init__(self, arr=[]): 23 | self._stack = list(arr) 24 | self._len = len(self._stack) 25 | 26 | def pop(self): 27 | if self._len == 0: 28 | raise ValueError("Stack is empty") 29 | 30 | v = self._stack.pop() 31 | self._len -= 1 32 | return v 33 | 34 | def push(self, v): 35 | self._stack.append(v) 36 | self._len += 1 37 | 38 | def is_empty(self): 39 | return self._len == 0 40 | 41 | 42 | def match(string): 43 | checker = Stack() 44 | 45 | for br in string: 46 | if br in OPENS: 47 | checker.push(br) 48 | else: 49 | if checker.is_empty(): 50 | return False 51 | oppo = checker.pop() 52 | if OPENS.index(oppo) != CLOSES.index(br): 53 | return False 54 | 55 | return checker.is_empty() 56 | 57 | 58 | if __name__ == '__main__': 59 | C = int(input()) 60 | ans = [] 61 | 62 | for _ in range(C): 63 | sample = input() 64 | ans.append(match(sample)) 65 | 66 | for n in ans: 67 | print('YES' if n == True else 'NO') 68 | -------------------------------------------------------------------------------- /problems_solving/algospot/childrenday.py: -------------------------------------------------------------------------------- 1 | """Return number of gifts for children in Christmas day 2 | 3 | :input: 4 | 5 5 | 1 7 0 6 | 1 10 1 7 | 0 7 3 8 | 345 9997 3333 9 | 35 9 8 10 | 11 | :return: 12 | 111111 13 | 11 14 | IMPOSSIBLE 15 | 35355353545 16 | 35 17 | 18 | 19 | url: https://algospot.com/judge/problem/read/CHILDRENDAY 20 | ID : CHILDRENDAY 21 | """ 22 | def append(here, edge, mod): 23 | there = here * 10 + edge 24 | if there >= mod: 25 | return mod + there % mod 26 | return there % mod 27 | 28 | 29 | def gifts(digits, n, m): 30 | digits = sorted(digits) 31 | parents = [-1] * n * 2 32 | choice = [-1] * n * 2 33 | queue = [0] 34 | parents[0] = 0 35 | 36 | while queue: 37 | here = queue.pop(0) 38 | for d in digits: 39 | there = append(here, int(d), n) 40 | if parents[there] == -1: 41 | parents[there] = here 42 | choice[there] = d 43 | queue.append(there) 44 | 45 | if parents[n+m] == -1: 46 | return "IMPOSSIBLE" 47 | 48 | ret = '' 49 | here = n + m 50 | while parents[here] != here: 51 | ret += choice[here] 52 | here = parents[here] 53 | 54 | return ret[::-1] 55 | 56 | 57 | if __name__ == '__main__': 58 | C = int(input()) 59 | ans = [] 60 | 61 | for _ in range(C): 62 | d, n, m = (int(n) for n in input().strip().split()) 63 | ans.append(gifts(str(d), n, m)) 64 | 65 | for n in ans: 66 | print(n) 67 | -------------------------------------------------------------------------------- /problems_solving/algospot/christmas.py: -------------------------------------------------------------------------------- 1 | """Return ways to buy christams gifts for good children 2 | 3 | :input: 4 | 1 5 | 6 4 6 | 1 2 3 4 5 6 7 | 8 | :return: 9 | 3 1 10 | 11 | url: https://algospot.com/judge/problem/read/CHRISTMAS 12 | ID : CHRISTMAS 13 | """ 14 | def ways_buying(p_gifts, K): 15 | MOD = 20091101 16 | counter = [0 for _ in range(K)] 17 | ret = 0 18 | 19 | for i in range(len(p_gifts)): 20 | counter[p_gifts[i]] += 1 21 | 22 | for i in range(K): 23 | if counter[i] >= 2: 24 | ret = (ret + ((counter[i] * (counter[i] - 1)) // 2)) % MOD 25 | return ret 26 | 27 | 28 | def max_buys(p_gifts, K): 29 | ret = [0 for _ in range(len(p_gifts))] 30 | prev = [-1 for _ in range(K)] 31 | 32 | for i in range(len(p_gifts)): 33 | if i > 0: 34 | ret[i] = ret[i-1] 35 | else: 36 | ret[i] = 0 37 | 38 | loc = prev[p_gifts[i]] 39 | if loc != -1: 40 | ret[i] = max(ret[i], ret[loc]+1) 41 | prev[p_gifts[i]] = i 42 | 43 | return ret[-1] 44 | 45 | 46 | if __name__ == '__main__': 47 | C = int(input()) 48 | for _ in range(C): 49 | N, K = (int(n) for n in input().split()) 50 | gifts = [int(n) for n in input().split()] 51 | 52 | p_gifts = [0] 53 | for n in gifts: 54 | p_gifts.append((p_gifts[-1] + n) % K) 55 | 56 | print(ways_buying(p_gifts, K), max_buys(p_gifts, K)) 57 | -------------------------------------------------------------------------------- /problems_solving/algospot/clocksync.py: -------------------------------------------------------------------------------- 1 | """Return the least number of swithces to make all clocks to 12 o'clock 2 | 3 | :input: 4 | 2 5 | 12 6 6 6 6 6 12 12 12 12 12 12 12 12 12 12 6 | 12 9 3 12 6 6 9 3 12 9 12 9 12 12 6 6 7 | 8 | :return: 9 | 2 10 | 9 11 | 12 | ID : CLOCKSYNC 13 | url: https://algospot.com/judge/problem/read/CLOCKSYNC 14 | """ 15 | import time 16 | 17 | 18 | SWITCHES = [[0, 1, 2], 19 | [3, 7, 9, 11], 20 | [4, 10, 14, 15], 21 | [0, 4, 5, 6, 7], 22 | [6, 7, 8, 10, 12], 23 | [0, 2, 14, 15], 24 | [3, 14, 15], 25 | [4, 5, 7, 14, 15], 26 | [1, 2, 3, 4, 5], 27 | [3, 4, 5, 9, 13], 28 | ] 29 | 30 | 31 | def algospot_n_clock(now): 32 | stime = time.time() 33 | N = len(SWITCHES) 34 | INF = 987654321 35 | 36 | def push(now, switch): 37 | for t in SWITCHES[switch]: 38 | now[t] += 3 39 | if now[t] == 15: 40 | now[t] = 3 41 | 42 | def solve(now, switch): 43 | if switch == N: 44 | return 0 if all(t == 12 for t in now) else INF 45 | ret = INF 46 | 47 | for cnt in range(4): 48 | ret = min(ret, cnt + solve(now, switch+1)) 49 | push(now, switch) 50 | 51 | return ret if ret != INF else -1 52 | 53 | ret = solve(now, 0) 54 | etime = time.time() 55 | print('-' * 40) 56 | print('Total time is', etime - stime) 57 | print('-' * 40) 58 | return ret 59 | 60 | 61 | if __name__ == '__main__': 62 | C = int(input()) 63 | ans = [] 64 | for _ in range(C): 65 | now = [int(n) for n in input().split()] 66 | ans.append(solve(now)) 67 | 68 | for n in ans: 69 | print(n) 70 | -------------------------------------------------------------------------------- /problems_solving/algospot/combinations_exhaust_search.py: -------------------------------------------------------------------------------- 1 | """Get all possible number of cases when n and r are given 2 | 3 | There are various ways to get combinations. 4 | Here, I implement with exhaust search(Brute force) 5 | """ 6 | def combinations(n, r, filled=None): 7 | if r > n: 8 | raise ValueError("r can't be greater than n") 9 | if r == 0: 10 | print(filled) 11 | return 12 | filled = filled if filled else [] 13 | smallest = 0 if not filled else filled[-1] + 1 14 | 15 | for nxt in range(smallest, n): 16 | filled.append(nxt) 17 | combinations(n, r-1, filled) 18 | filled.pop() 19 | 20 | 21 | if __name__ == '__main__': 22 | combinations(10, 3) 23 | combinations(1, 1) 24 | -------------------------------------------------------------------------------- /problems_solving/algospot/data: -------------------------------------------------------------------------------- 1 | 2 2 | 3 3 | 5 5 15 4 | 5 5 10 5 | 5 5 5 6 | 8 7 | 21 15 20 8 | 15 15 10 9 | 13 12 5 10 | 12 12 3 11 | 19 19 2 12 | 30 24 5 13 | 32 10 7 14 | 32 9 4 15 | -------------------------------------------------------------------------------- /problems_solving/algospot/dragon.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | :input: 4 | 4 5 | 0 1 2 6 | 1 1 5 7 | 2 6 5 8 | 42 764853475 30 9 | 10 | :return: 11 | FX 12 | FX+YF 13 | +FX-Y 14 | FX-YF-FX+YF+FX-YF-FX+YF-FX-YF- 15 | """ 16 | def dragon(seed, generations): 17 | if generations == 0: 18 | return seed 19 | ans = '' 20 | 21 | for i in range(len(seed)): 22 | if seed[i] == 'X': 23 | ans += dragon_maker('X+YF', generations-1) 24 | elif seed[i] == 'Y': 25 | ans += dragon_maker('FX-Y', generations-1) 26 | else: 27 | ans += seed[i] 28 | return ans 29 | 30 | 31 | def dragon_maker(seed, generations, p, l): 32 | EXPAND_X = 'X+YF' 33 | EXPAND_Y = 'FX-Y' 34 | len_cache = [-1 for _ in range(generations+1)] 35 | len_cache[0] = 1 36 | ans = '' 37 | 38 | for i in range(1, generations+1): 39 | len_cache[i] = len_cache[i-1] * 2 + 2 40 | 41 | def expand(string, generations, skip): 42 | if generations == 0: 43 | return string[skip] if skip < len(string) else '' 44 | 45 | for i in range(len(string)): 46 | if string[i] == 'X' or string[i] == 'Y': 47 | if skip >= len_cache[generations]: 48 | skip -= len_cache[generations] 49 | elif string[i] == 'X': 50 | return expand(EXPAND_X, generations-1, skip) 51 | else: 52 | return expand(EXPAND_Y, generations-1, skip) 53 | elif skip > 0: 54 | skip -= 1 55 | else: 56 | return string[i] 57 | 58 | for i in range(l): 59 | ans += expand(seed, generations, p-1+i) 60 | return ans 61 | 62 | 63 | if __name__ == '__main__': 64 | C = int(input()) 65 | ans = [] 66 | 67 | for _ in range(C): 68 | n, p, l = (int(n) for n in input().split()) 69 | ans.append(dragon_maker('FX', n, p, l)) 70 | 71 | for n in ans: 72 | print(n) 73 | -------------------------------------------------------------------------------- /problems_solving/algospot/fence.py: -------------------------------------------------------------------------------- 1 | """Get the maximum area of the bars standing side by side 2 | 3 | ID : FENCE 4 | 5 | https://algospot.com/judge/problem/read/FENCE 6 | """ 7 | def solve(left: int, right: int): 8 | if left == right: 9 | return heights[left] 10 | 11 | mid = (left + right) // 2 12 | ans = max(solve(left, mid), solve(mid+1, right)) 13 | 14 | lo, hi = mid, mid + 1 15 | height = min(heights[lo], heights[hi]) 16 | ans = max(ans, height * 2) 17 | 18 | while left < lo or hi < right: 19 | if hi < right and (lo == left or heights[lo-1] < heights[hi+1]): 20 | hi += 1 21 | height = min(height, heights[hi]) 22 | else: 23 | lo -= 1 24 | height = min(height, heights[lo]) 25 | 26 | ans = max(ans, height * (hi - lo +1)) 27 | 28 | return ans 29 | 30 | 31 | C = int(input()) 32 | ans_list = [] 33 | for _ in range(C): 34 | input() 35 | heights = [int(x) for x in input().split()] 36 | ans_list.append(solve(0, len(heights)-1)) 37 | 38 | for n in ans_list: 39 | print(n) 40 | -------------------------------------------------------------------------------- /problems_solving/algospot/gallery.py: -------------------------------------------------------------------------------- 1 | """Return number of cameras to cover all area of the gallery 2 | 3 | :input: 4 | 3 5 | 6 5 6 | 0 1 7 | 1 2 8 | 1 3 9 | 2 5 10 | 0 4 11 | 4 2 12 | 0 1 13 | 2 3 14 | 1000 1 15 | 0 1 16 | 17 | :return: 18 | 3 19 | 2 20 | 999 21 | 22 | url: https://algospot.com/judge/problem/read/GALLERY 23 | ID : GALLERY 24 | """ 25 | def number_of_cameras(graph): 26 | V = len(graph) 27 | visited = [0] * V 28 | UNWATCHED = 0 29 | WATCHED = 1 30 | INSTALLED = 2 31 | total_installed = 0 32 | 33 | def dfs(here): 34 | nonlocal total_installed 35 | visited[here] = True 36 | children = [0, 0, 0] 37 | for there in graph[here]: 38 | if not visited[there]: 39 | children[dfs(there)] += 1 40 | 41 | if children[UNWATCHED]: 42 | total_installed += 1 43 | return INSTALLED 44 | 45 | if children[INSTALLED]: 46 | return WATCHED 47 | return UNWATCHED 48 | 49 | for u in range(V): 50 | if not visited[u] and dfs(u) == UNWATCHED: 51 | total_installed += 1 52 | 53 | return total_installed 54 | 55 | 56 | if __name__ == '__main__': 57 | C = int(input()) 58 | ans = [] 59 | 60 | for _ in range(C): 61 | V, E = (int(n) for n in input().split()) 62 | graph = [[] for _ in range(V)] 63 | for _ in range(E): 64 | a, b = (int(n) for n in input().split()) 65 | graph[a].append(b) 66 | graph[b].append(a) 67 | 68 | ans.append(number_of_cameras(graph)) 69 | 70 | for n in ans: 71 | print(n) 72 | -------------------------------------------------------------------------------- /problems_solving/algospot/genius.py: -------------------------------------------------------------------------------- 1 | """Return possibilities of songs being played in a specific time 2 | 3 | :input: 4 | 3 5 | 3 6 3 6 | 4 4 2 7 | 0.18 0.40 0.42 8 | 0.15 0.46 0.39 9 | 0.58 0.23 0.19 10 | 0 1 2 11 | 4 10 4 12 | 1 3 2 4 13 | 0.26 0.07 0.49 0.18 14 | 0.21 0.33 0.15 0.31 15 | 0.41 0.20 0.38 0.01 16 | 0.28 0.31 0.18 0.23 17 | 2 0 3 1 18 | 4 1000 4 19 | 4 3 4 4 20 | 0.08 0.47 0.12 0.33 21 | 0.10 0.02 0.39 0.49 22 | 0.08 0.33 0.35 0.24 23 | 0.14 0.19 0.58 0.09 24 | 1 3 2 0 25 | 26 | :return: 27 | 0.42360000 0.49660000 0.07980000 28 | 0.31060929 0.13791635 0.26756048 0.28391388 29 | 0.18648004 0.28409359 0.42243515 0.10699122 30 | """ 31 | def get_prb(K, wanted, song_length, T): 32 | N = len(song_length) 33 | cache = [[0 for _ in range(N)] for _ in range(5)] 34 | cache[0][0] = 1.0 35 | probs = [0 for _ in range(N)] 36 | ret = [] 37 | 38 | for time in range(1, K+1): 39 | for nxt in range(N): 40 | tmp = 0 41 | for prev in range(N): 42 | tmp += cache[(time-song_length[prev]+5) % 5][prev] * T[prev][nxt] 43 | cache[time % 5][nxt] = tmp 44 | 45 | for song in range(N): 46 | for start in range(K-song_length[song]+1, K+1): 47 | probs[song] += cache[start % 5][song] 48 | 49 | for m in wanted: 50 | ret.append(probs[m]) 51 | 52 | return ret 53 | 54 | 55 | if __name__ == '__main__': 56 | C = int(input()) 57 | ans = [] 58 | 59 | for _ in range(C): 60 | N, K, M = [int(n) for n in input().split()] 61 | T = [None for _ in range(N)] 62 | song_length = [int(n) for n in input().split()] 63 | for i in range(N): 64 | T[i] = [float(n) for n in input().split()] 65 | 66 | wanted = [int(n) for n in input().split()] 67 | ans.append(get_prb(K, wanted, song_length, T)) 68 | 69 | for n in ans: 70 | print(' '.join(str(c) for c in n)) 71 | -------------------------------------------------------------------------------- /problems_solving/algospot/ites.py: -------------------------------------------------------------------------------- 1 | """Return number of connected subsequences that sum up to K 2 | 3 | :input: 4 | 3 5 | 8791 20 6 | 5265 5000 7 | 3578452 5000000 8 | 9 | :return: 10 | 1 11 | 4 12 | 1049 13 | 14 | url: https://algospot.com/judge/problem/read/ITES 15 | ID : ITES 16 | """ 17 | # Unefficient offline solution 18 | def offline_solution(signals, k): 19 | ret = 0 20 | N = len(signals) 21 | 22 | for s in range(N): 23 | tmp_sum = 0 24 | for e in range(s, N): 25 | tmp_sum += signals[e] 26 | if tmp_sum == k: 27 | ret += 1 28 | if tmp_sum >= k: 29 | break 30 | return ret 31 | 32 | 33 | class Queue: 34 | def __init__(self, arr=[]): 35 | self._len = len(arr) 36 | self._queue = list(arr) 37 | 38 | def is_empty(self): 39 | return self._len == 0 40 | 41 | def pop(self): 42 | if self.is_empty(): 43 | raise ValueError("Queue is empty") 44 | 45 | self._len -= 1 46 | return self._queue.pop(0) 47 | 48 | def push(self, v): 49 | self._len += 1 50 | self._queue.append(v) 51 | 52 | 53 | 54 | 55 | def signal_generator(N): 56 | seed = 1983 57 | for _ in range(N): 58 | yield seed % 10000 + 1 59 | seed = (seed * 214013 + 2531011) % (2 ** 32) 60 | 61 | 62 | # It goes down to better solution below 63 | def optimized_solution(N, k): 64 | ret, tail = 0, 0 65 | tmp_sum = 0 66 | queue = Queue() 67 | generator = signal_generator(N) 68 | 69 | for i in range(N): 70 | new_signal = next(generator) 71 | tmp_sum += new_signal 72 | queue.push(new_signal) 73 | 74 | while tmp_sum > k: 75 | tmp_sum -= queue.pop() 76 | 77 | if tmp_sum == k: 78 | ret += 1 79 | return ret 80 | 81 | 82 | if __name__ == '__main__': 83 | C = int(input()) 84 | ans = [] 85 | 86 | for _ in range(C): 87 | K, N = (int(n) for n in input().split()) 88 | ans.append(optimized_solution(N, K)) 89 | 90 | for n in ans: 91 | print(n) 92 | -------------------------------------------------------------------------------- /problems_solving/algospot/jaehasafe.py: -------------------------------------------------------------------------------- 1 | """Return least number of shifts to open safe 2 | 3 | :input: 4 | 2 5 | 3 6 | abbab 7 | babab 8 | ababb 9 | bbaba 10 | 2 11 | RMDCMRCD 12 | MRCDRMDC 13 | DCMRCDRM 14 | 15 | :return: 16 | 6 17 | 10 18 | 19 | url: https://algospot.com/judge/problem/read/JAEHASAFE 20 | ID : JAEHASAFE 21 | """ 22 | def kmp_search(h, n): 23 | h_len, n_len = len(h), len(n) 24 | begin, matched = 0, 0 25 | pos = [] 26 | 27 | def partial_match(s): 28 | begin, matched = 1, 0 29 | ret = [0] * (n_len + 1) 30 | while begin + matched < n_len: 31 | if s[begin+matched] == s[matched]: 32 | matched += 1 33 | ret[begin+matched] = matched 34 | else: 35 | if matched == 0: 36 | begin += 1 37 | else: 38 | begin += matched - ret[matched] 39 | matched = ret[matched] 40 | return ret 41 | 42 | pi = partial_match(n) 43 | while begin <= h_len - n_len: 44 | if matched < n_len and h[begin + matched] == n[matched]: 45 | matched += 1 46 | if matched == n_len: 47 | pos.append(begin) 48 | else: 49 | if matched == 0: 50 | begin += 1 51 | else: 52 | begin += matched - pi[matched] 53 | matched = pi[matched] 54 | return pos 55 | 56 | 57 | def jaehasafe(states): 58 | ans = 0 59 | right = True 60 | for i in range(len(states)-1): 61 | if right: 62 | ans += kmp_search(states[i+1] * 2, states[i])[0] 63 | else: 64 | ans += kmp_search(states[i] * 2, states[i+1])[0] 65 | right ^= True 66 | return ans 67 | 68 | 69 | if __name__ == '__main__': 70 | C = int(input()) 71 | ans = [] 72 | for _ in range(C): 73 | states = [] 74 | N = int(input()) 75 | for _ in range(N+1): 76 | states.append(input()) 77 | ans.append(jaehasafe(states)) 78 | for n in ans: 79 | print(n) 80 | -------------------------------------------------------------------------------- /problems_solving/algospot/josephus.py: -------------------------------------------------------------------------------- 1 | """Get locations to be last two men standing 2 | 3 | :input: 4 | 2 5 | 6 3 6 | 40 3 7 | 8 | :return: 9 | 3 5 10 | 11 26 11 | 12 | url: https://algospot.com/judge/problem/read/JOSEPHUS 13 | ID : JOSEPHUS 14 | """ 15 | def not_effective_last_men_standing_by_park(N, K): 16 | alive = N 17 | check = [1 for _ in range(N+1)] 18 | 19 | check[0] = check[1] = 0 20 | alive -= 1 21 | last = 1 22 | ans = [] 23 | 24 | while alive > 2: 25 | skip = K 26 | i = 0 27 | 28 | while skip != 0: 29 | if check[(last+i) % N+1] == 1: 30 | skip -= 1 31 | i += 1 32 | i -= 1 33 | 34 | check[(last+i) % N+1] = 0 35 | last = (last+i) % N + 1 36 | alive -= 1 37 | 38 | for i, n in enumerate(check): 39 | if n == 1: 40 | ans.append(i) 41 | 42 | return ans 43 | 44 | 45 | def josephus(N, STRIDE, idx_start_from_1=True): 46 | still_alive = list(range(N)) 47 | kill = 0 48 | 49 | while len(still_alive) > 2: 50 | still_alive.pop(kill) 51 | kill = (kill + STRIDE - 1) % len(still_alive) 52 | 53 | if idx_start_from_1: 54 | return [n + 1 for n in still_alive] 55 | else: 56 | return still_alive 57 | 58 | 59 | if __name__ == '__main__': 60 | C = int(input()) 61 | ans = [] 62 | 63 | for _ in range(C): 64 | N, STRIDE = (int(n) for n in input().split()) 65 | ans.append(josephus(N, STRIDE, idx_start_from_1=True)) 66 | 67 | for a, b in ans: 68 | print(a, b) 69 | -------------------------------------------------------------------------------- /problems_solving/algospot/jumpgame.py: -------------------------------------------------------------------------------- 1 | """Check if you can reach the last point of the matrix from the 0, 0 point 2 | 3 | ID : JUMPGAMe 4 | URL: https://algospot.com/judge/problem/read/JUMPGAME 5 | """ 6 | def jump(y, x): 7 | global cache 8 | if y >= N or x >= N: 9 | return 0 10 | if y == N - 1 and x == N - 1: 11 | return 1 12 | if cache[y][x] != -1: 13 | return cache[y][x] 14 | d = matrix[y][x] 15 | cache[y][x] = jump(y+d, x) or jump(y, x+d) 16 | return cache[y][x] 17 | 18 | 19 | C = int(input()) 20 | ans = [] 21 | 22 | for _ in range(C): 23 | N = int(input()) 24 | matrix = [] 25 | cache = [[-1 for _ in range(N)] for _ in range(N)] 26 | for _ in range(N): 27 | matrix.append([int(x) for x in input().split()]) 28 | ans.append('YES' if jump(0, 0) else 'NO') 29 | 30 | for a in ans: 31 | print(a) 32 | -------------------------------------------------------------------------------- /problems_solving/algospot/kmp.py: -------------------------------------------------------------------------------- 1 | """Implement KMP substring search algorithm""" 2 | def inefficient_search(h, n): 3 | ans = 0 4 | pos = [] 5 | for i in range(len(h)-len(n)+1): 6 | matched = True 7 | for j in range(len(n)): 8 | if h[i+j] != n[j]: 9 | matched = False 10 | break 11 | if matched: 12 | ans += 1 13 | pos.append(i) 14 | return ans, pos 15 | 16 | # This simple algorithm works, but time complexity is O(|H| * |N|) 17 | # '|X|' means length of X 18 | 19 | 20 | # However, this algorithm, KMP can make it simple 21 | def kmp_search(H, N): 22 | h_len, n_len = len(H), len(N) 23 | count, pos = 0, [] 24 | begin, matched = 0, 0 25 | 26 | def generate_partial(N): 27 | begin, matched = 1, 0 28 | ret = [0] * (n_len+1) 29 | 30 | while begin + matched < n_len: 31 | if N[begin+matched] == N[matched]: 32 | matched += 1 33 | ret[begin+matched] = matched 34 | else: 35 | if matched == 0: 36 | begin += 1 37 | else: 38 | begin += matched - ret[matched] 39 | matched = ret[matched] 40 | return ret 41 | 42 | 43 | pi = generate_partial(N) 44 | 45 | while begin <= h_len - n_len: 46 | if matched < n_len and H[begin + matched] == N[matched]: 47 | matched += 1 48 | if matched == n_len: 49 | count += 1 50 | pos.append(begin) 51 | else: 52 | if matched == 0: 53 | begin += 1 54 | else: 55 | begin += matched - pi[matched] 56 | matched = pi[matched] 57 | 58 | return count, pos 59 | -------------------------------------------------------------------------------- /problems_solving/algospot/lunchbox.py: -------------------------------------------------------------------------------- 1 | """Return the minimal time of finishing lunch time 2 | 3 | :input: 4 | 2 5 | 3 6 | 2 2 2 7 | 2 2 2 8 | 3 9 | 1 2 3 10 | 1 2 1 11 | 12 | :return: 13 | 8 14 | 7 15 | """ 16 | def min_time(pairs): 17 | ret, begin_eat = 0, 0 18 | # pairs: list of (e, h) 19 | for i in range(len(pairs)): 20 | begin_eat += pairs[i][1] 21 | ret = max(ret, begin_eat + pairs[i][0]) 22 | return ret 23 | 24 | 25 | if __name__ == '__main__': 26 | C = int(input()) 27 | ans = [] 28 | for _ in range(C): 29 | N = int(input()) 30 | H = [int(n) for n in input().split()] 31 | E = [int(n) for n in input().split()] 32 | pairs = [(e, h) for e, h in zip(E, H)] 33 | pairs.sort(reverse=True) 34 | ans.append(min_time(pairs)) 35 | 36 | for n in ans: 37 | print(n) 38 | -------------------------------------------------------------------------------- /problems_solving/algospot/matchorder.py: -------------------------------------------------------------------------------- 1 | """Return maximum number of wins 2 | 3 | :input: 4 | 3 5 | 6 6 | 3000 2700 2800 2200 2500 1900 7 | 2800 2750 2995 1800 2600 2000 8 | 3 9 | 1 2 3 10 | 3 2 1 11 | 4 12 | 2 3 4 5 13 | 1 2 3 4 14 | 15 | :return: 16 | 5 17 | 3 18 | 3 19 | 20 | url: https://algospot.com/judge/problem/read/MATCHORDER 21 | ID : MATCHORDER 22 | """ 23 | def max_wins(russians, koreans): 24 | koreans.sort() 25 | wins = 0 26 | # 1. 절대 못 이기는 놈이면 제일 약한 애를 매칭시킨다. 27 | # 2. 그래도 이길 수는 있으면 그 러시안 친구보다 강한 가장 약한 친구들 내보낸다. 28 | rm_kor = 0 29 | for i in range(len(russians)): 30 | if russians[i] > koreans[-1]: 31 | rm_kor = 0 32 | else: 33 | for j in range(len(koreans)): 34 | if russians[i] <= koreans[j]: 35 | wins += 1 36 | rm_kor = j 37 | break 38 | koreans.pop(rm_kor) 39 | 40 | return wins 41 | 42 | 43 | 44 | if __name__ == '__main__': 45 | C = int(input()) 46 | ans = [] 47 | for _ in range(C): 48 | N = int(input()) 49 | russians = [int(n) for n in input().split()] 50 | koreans = [int(n) for n in input().split()] 51 | ans.append(max_wins(russians, koreans)) 52 | 53 | for n in ans: 54 | print(n) 55 | -------------------------------------------------------------------------------- /problems_solving/algospot/minastirith.py: -------------------------------------------------------------------------------- 1 | """Return the minimal number of soliders need to cover all ramparts of the city 2 | 3 | :input: 4 | 3 5 | 10 6 | 7.02066050 -3.83540431 4.0 7 | -7.23257714 -3.41903904 2.0 8 | 0.00000000 -8.00000000 8.0 9 | -8.00000000 -0.00000000 4.8 10 | -6.47213595 4.70228202 3.2 11 | -4.70228202 6.47213595 4.8 12 | 7.60845213 -2.47213595 1.6 13 | -2.47213595 -7.60845213 8.8 14 | 6.47213595 4.70228202 7.6 15 | -0.00000000 8.00000000 4.8 16 | 4 17 | 8.00000000 0.00000000 8.00 18 | 0.00000000 -8.00000000 8.00 19 | -8.00000000 -0.00000000 8.00 20 | 1.25147572 7.90150672 5.40 21 | 1 22 | 8 0 15.99 23 | 24 | :return: 25 | 5 26 | 4 27 | IMPOSSIBLE 28 | 29 | url: https://algospot.com/judge/problem/read/MINASTIRITH 30 | ID : MINASTIRITH 31 | """ 32 | import math 33 | 34 | 35 | def num_guards(points): 36 | # points: | A list of (y, x, r) tuple 37 | rngs = [] 38 | 39 | def convert_to_range(): 40 | for y, x, r in points: 41 | loc = math.atan2(y, x) + math.pi 42 | rng = 2.0 * math.asin(r / 2.0 / 8.0) 43 | rng.append(loc-rng, loc+rng) 44 | rng.sort() 45 | 46 | convert_to_range() 47 | 48 | 49 | 50 | 51 | if __name__ == '__main__': 52 | C = int(input()) 53 | ans = [] 54 | for _ in range(C): 55 | N = int(input()) 56 | points = [] 57 | for _ in range(N): 58 | y, x, r = (float(n) for n in input().split()) 59 | points.append((y, x, r)) 60 | ans.append(num_guards(points)) 61 | 62 | for n in ans: 63 | print(n) 64 | 65 | -------------------------------------------------------------------------------- /problems_solving/algospot/naming.py: -------------------------------------------------------------------------------- 1 | """Return lengths of all possible names 2 | 3 | :input: 4 | ababcabababa 5 | bcabab 6 | 7 | :return: 8 | 2 4 9 18 9 | 10 | url: https://algospot.com/judge/problem/read/NAMING 11 | ID : NAMING 12 | """ 13 | def get_presuffix_len(s): 14 | N = len(s) 15 | ret = [0] * (N+1) 16 | begin, matched = 1, 0 17 | 18 | while begin + matched < N: 19 | if s[begin+matched] == s[matched]: 20 | matched += 1 21 | ret[begin+matched] = matched 22 | else: 23 | if not matched: 24 | begin += 1 25 | else: 26 | begin += matched - ret[matched] 27 | matched = ret[matched] 28 | return ret 29 | 30 | 31 | def length_names(t): 32 | pi = get_presuffix_len(t) 33 | k = len(t) 34 | ans = [] 35 | 36 | while k: 37 | ans.append(k) 38 | k = pi[k] 39 | 40 | ans.sort() 41 | return ans 42 | 43 | 44 | if __name__ == '__main__': 45 | F = input() 46 | M = input() 47 | t = F + M 48 | ans = length_names(t) 49 | print(' '.join(str(c) for c in ans)) 50 | -------------------------------------------------------------------------------- /problems_solving/algospot/numbergame.py: -------------------------------------------------------------------------------- 1 | """Return the maximum differential of scores when 2 players play their best 2 | 3 | :input: 4 | 5 | 3 6 | 5 7 | -1000 -1000 -3 -1000 -1000 8 | 6 9 | 100 -1000 -1000 100 -1000 -1000 10 | 10 11 | 7 -5 8 5 1 -4 -8 6 7 9 12 | 13 | :return: 14 | -1000 15 | 1100 16 | 7 17 | 18 | ID : NUMBERGAME 19 | url: https://algospot.com/judge/problem/read/NUMBERGAME 20 | """ 21 | def score_diff(arr): 22 | length = len(arr) 23 | EMPTY = -987654321 24 | cache = [[EMPTY for _ in range(length)] for _ in range(length)] 25 | 26 | def play(left, right): 27 | if left > right: 28 | return 0 29 | elif cache[left][right] != EMPTY: 30 | return cache[left][right] 31 | ret = max(arr[left] - play(left+1, right), 32 | arr[right] - play(left, right-1)) 33 | 34 | if right - left + 1 >= 2: 35 | ret = max(ret, -play(left+2, right), -play(left, right-2)) 36 | cache[left][right] = ret 37 | return ret 38 | 39 | return play(0, length-1) 40 | 41 | 42 | if __name__ == '__main__': 43 | C = int(input()) 44 | ans = [] 45 | for _ in range(C): 46 | input() 47 | arr = [int(n) for n in input().split()] 48 | ans.append(score_diff(arr)) 49 | 50 | for n in ans: 51 | print(n) 52 | -------------------------------------------------------------------------------- /problems_solving/algospot/palindromize.py: -------------------------------------------------------------------------------- 1 | """Return length of shortest palindrome with given string 2 | 3 | :input: 4 | 3 5 | there 6 | amanaplanacanal 7 | xyz 8 | 9 | :return: 10 | 7 11 | 21 12 | 5 13 | 14 | url: https://algospot.com/judge/problem/read/PALINDROMIZE 15 | ID : PALINDROMIZE 16 | """ 17 | from sys import stdin 18 | 19 | 20 | 21 | def reverse(s): 22 | ret = '' 23 | N = len(s) 24 | for i in range(N): 25 | ret += s[N-1-i] 26 | return ret 27 | 28 | 29 | def generate_partial(s): 30 | N = len(s) 31 | ret = [0] * (N+1) 32 | begin, matched = 1, 0 33 | 34 | while begin + matched < N: 35 | if s[begin + matched] == s[matched]: 36 | matched += 1 37 | ret[begin+matched] = matched 38 | else: 39 | if matched == 0: 40 | begin += 1 41 | else: 42 | begin += matched - ret[matched] 43 | matched = ret[matched] 44 | return ret 45 | 46 | 47 | def len_palindrome(s): 48 | rs = reverse(s) 49 | pi_rs = generate_partial(rs) 50 | N = len(s) 51 | begin = 0 52 | matched = 0 53 | rs_len = 0 54 | 55 | while begin + matched < N: 56 | if matched < N and s[begin + matched] == rs[matched]: 57 | matched += 1 58 | if begin + matched == N: 59 | rs_len = matched 60 | break 61 | else: 62 | if matched == 0: 63 | begin += 1 64 | else: 65 | begin += matched - pi_rs[matched] 66 | matched = pi_rs[matched] 67 | 68 | return N * 2 - rs_len 69 | 70 | 71 | if __name__ == '__main__': 72 | C = int(stdin.readline()) 73 | ans = [] 74 | for _ in range(C): 75 | word = stdin.readline().strip() 76 | ans.append(len_palindrome(word)) 77 | 78 | for n in ans: 79 | print(n) 80 | -------------------------------------------------------------------------------- /problems_solving/algospot/picnic.py: -------------------------------------------------------------------------------- 1 | """Solve algospot picnic problem 2 | 3 | :input: 4 | 3 5 | 2 1 6 | 0 1 7 | 4 6 8 | 0 1 1 2 2 3 3 0 0 2 1 3 9 | 6 10 10 | 0 1 0 2 1 2 1 3 1 4 2 3 2 4 3 4 3 5 4 5 11 | 12 | :output: 13 | 1 14 | 3 15 | 4 16 | 17 | ID : PICNIC 18 | url: https://algospot.com/judge/problem/read/PICNIC 19 | """ 20 | def get_ways(are_friends): 21 | N = len(are_friends) 22 | taken = [0] * N 23 | 24 | def find(left): 25 | if left == 0: 26 | return 1 27 | 28 | for i in range(N): 29 | if not taken[i]: 30 | nxt = i 31 | break 32 | 33 | ans = 0 34 | for i in range(nxt+1, N): 35 | if not taken[i] and are_friends[i][nxt]: 36 | taken[i] = 1 37 | taken[nxt] = 1 38 | ans += find(left-2) 39 | taken[i] = 0 40 | taken[nxt] = 0 41 | return ans 42 | 43 | return find(N) 44 | 45 | 46 | if __name__ == '__main__': 47 | C = int(input()) 48 | ans = [] 49 | 50 | for _ in range(C): 51 | n, m = (int(n) for n in input().split()) 52 | are_friends = [[0] * n for _ in range(n)] 53 | rels = [int(n) for n in input().split()] 54 | i = 0 55 | 56 | while i < len(rels): 57 | are_friends[rels[i]][rels[i+1]] = 1 58 | are_friends[rels[i+1]][rels[i]] = 1 59 | i += 2 60 | 61 | ans.append(get_ways(are_friends)) 62 | 63 | for n in ans: 64 | print(n) 65 | 66 | -------------------------------------------------------------------------------- /problems_solving/algospot/polynomio.py: -------------------------------------------------------------------------------- 1 | """Return the number of monotonic polynomios when number of squares are given 2 | 3 | If answer is bigger than 1e7, return the modulo by 1e7. 4 | 5 | :input: 6 | 3 7 | 2 8 | 4 9 | 92 10 | 11 | :return: 12 | 2 13 | 19 14 | 4841817 15 | 16 | ID : POLY 17 | url: https://algospot.com/judge/problem/read/POLY 18 | """ 19 | MOD = int(1e7) 20 | cache = [[-1 for _ in range(100+1)] for _ in range(100+1)] 21 | 22 | 23 | def mono_polynomios(n): 24 | def poly(n, this): 25 | global cache 26 | if n == this: 27 | return 1 28 | elif cache[n][this] != -1: 29 | return cache[n][this] 30 | else: 31 | cache[n][this] = sum((this+second-1) * poly(n-this, second) for second in range(1, n-this+1)) 32 | 33 | cache[n][this] %= MOD 34 | return cache[n][this] 35 | 36 | ans = 0 37 | for i in range(1, n+1): 38 | ans += poly(n, i) 39 | 40 | return ans % MOD 41 | 42 | 43 | if __name__ == '__main__': 44 | C = int(input()) 45 | ans = [] 46 | for _ in range(C): 47 | ans.append(mono_polynomios(int(input()))) 48 | 49 | for n in ans: 50 | print(n) 51 | -------------------------------------------------------------------------------- /problems_solving/algospot/potion.py: -------------------------------------------------------------------------------- 1 | """Get min amount of scoops to make up right bottle of potion 2 | 3 | :input: 4 | 3 5 | 4 6 | 4 6 2 4 7 | 6 4 2 4 8 | 4 9 | 4 6 2 4 10 | 7 4 2 4 11 | 3 12 | 4 5 6 13 | 1 2 3 14 | 15 | :return: 16 | 0 5 1 2 17 | 1 8 2 4 18 | 3 3 3 19 | 20 | url: https://algospot.com/judge/problem/read/POTION 21 | ID : POTION 22 | """ 23 | import math 24 | 25 | 26 | def gcd(a, b): 27 | return a if b == 0 else gcd(b, a % b) 28 | 29 | 30 | def min_scoop(reci, put): 31 | N = len(reci) 32 | ret = [0 for _ in range(N)] 33 | b = reci[0] 34 | 35 | for i in range(1, N): 36 | b = gcd(b, reci[i]) 37 | 38 | max_ratio = 0 39 | for i in range(N): 40 | max_ratio = max(max_ratio, put[i] / reci[i]) 41 | a = math.ceil(b * max_ratio) 42 | 43 | for i in range(N): 44 | ret[i] += int(reci[i] * a / b - put[i]) 45 | return ret 46 | 47 | 48 | 49 | if __name__ == '__main__': 50 | C = int(input()) 51 | ans = [] 52 | 53 | for _ in range(C): 54 | input() 55 | reci = [int(n) for n in input().split()] 56 | put = [int(n) for n in input().split()] 57 | ans.append(min_scoop(reci, put)) 58 | 59 | for n in ans: 60 | print(' '.join(str(c) for c in n)) 61 | -------------------------------------------------------------------------------- /problems_solving/algospot/quad_tree_reverse.py: -------------------------------------------------------------------------------- 1 | """Turn an image upside-down and change it into a string 2 | 3 | 4 | 'B' means a sector is all black and 'W' means a sector is all white. 5 | If it is 'X', it means at least one of 4 parts of the image has black and white together. 6 | 7 | So when I get the original compressed string of the image, 8 | I have to return a string of the turned out image. 9 | 10 | https://algospot.com/judge/problem/read/QUADTREE 11 | """ 12 | def decompress(compressed_img: list, pointer: int, y: int, x: int, size: int): 13 | char = compressed_img[pointer] 14 | pointer += 1 15 | if char == 'b' or char == 'w': 16 | for dy in range(size): 17 | for dx in range(size): 18 | image_board[y+dy][x+dx] = char 19 | else: 20 | half = size // 2 21 | decompress(compressed_img, pointer, y, x, half) 22 | decompress(compressed_img, pointer, y, x+half, half) 23 | decompress(compressed_img, pointer, y+half, x, half) 24 | decompress(compressed_img, pointer, y+half, x+half, half) 25 | 26 | 27 | def reverse_compressed_img(compressed_img): 28 | point = 0 29 | def _reverse(): 30 | nonlocal point 31 | head = compressed_img[point] 32 | point += 1 33 | if head == 'w' or head == 'b': 34 | return head 35 | upper_left = _reverse() 36 | upper_right = _reverse() 37 | lower_left = _reverse() 38 | lower_right = _reverse() 39 | 40 | return 'x' + lower_left + lower_right + upper_left + upper_right 41 | 42 | return _reverse() 43 | 44 | 45 | if __name__ == '__main__': 46 | tests = ['w', 'xbwwb', 'xbwxwbbwb', 'xxwwwbxwxwbbbwwxxxwwbbbwwwwbb'] 47 | for test in tests: 48 | print(reverse_compressed_img(test)) 49 | -------------------------------------------------------------------------------- /problems_solving/algospot/quantize.py: -------------------------------------------------------------------------------- 1 | """Get the smallest sum of min error when arr and split size is given 2 | 3 | ID : QUANTIZE 4 | url : https://algospot.com/judge/problem/read/QUANTIZE 5 | """ 6 | def get_smallest_minerror(arr, s): 7 | arr.sort() 8 | length = len(arr) 9 | cum_sum = [0 for _ in range(length)] 10 | cum_sq_sum = [0 for _ in range(length)] 11 | cum_sum[0] = arr[0] 12 | cum_sq_sum[0] = arr[0] * arr[0] 13 | cache = [[-1 for _ in range(s+1)] for _ in range(length+1)] 14 | 15 | for i in range(1, length): 16 | cum_sum[i] = cum_sum[i-1] + arr[i] 17 | cum_sq_sum[i] = cum_sq_sum[i-1] + arr[i] * arr[i] 18 | 19 | def min_error(lo, hi): 20 | p_sum = cum_sum[hi] - (cum_sum[lo-1] if lo != 0 else 0) 21 | p_sq_sum = cum_sq_sum[hi] - (cum_sq_sum[lo-1] if lo != 0 else 0) 22 | mean = round(p_sum / (hi - lo + 1)) 23 | 24 | ret = p_sq_sum - 2 * mean * p_sum + mean * mean * (hi-lo+1) 25 | return ret 26 | 27 | def quantize(_from, parts): 28 | if _from == length: 29 | return 0 30 | if parts == 0: 31 | return 987654321 32 | if cache[_from][parts] != -1: 33 | return cache[_from][parts] 34 | 35 | ret = 987654321 36 | for part_size in range(1, length-_from+1): 37 | ret = min(ret, min_error(_from, _from+part_size-1) + quantize(_from + part_size, 38 | parts-1)) 39 | cache[_from][parts] = ret 40 | return ret 41 | 42 | return quantize(0, s) 43 | 44 | 45 | if __name__ == '__main__': 46 | C = int(input()) 47 | ans = [] 48 | for _ in range(C): 49 | N, S = (int(x) for x in input().split()) 50 | arr = [int(n) for n in input().split()] 51 | ans.append(get_smallest_minerror(arr, S)) 52 | 53 | for n in ans: 54 | print(n) 55 | -------------------------------------------------------------------------------- /problems_solving/algospot/rock_festival.py: -------------------------------------------------------------------------------- 1 | """Find series of days which minimizes the average cost. 2 | 3 | 4 | ID : FESTIVAL 5 | https://algospot.com/judge/problem/read/FESTIVAL 6 | """ 7 | C = int(input()) 8 | min_lists = [] 9 | MAX_N = 1000 10 | 11 | def get_min_avg(N, L, costs): 12 | min_ave = MAX_N + 1 13 | for l in range(L, N+1): 14 | tmp = sum(costs[:l]) / l 15 | min_ave = min(min_ave, tmp) 16 | for i in range(N-l): 17 | tmp = tmp - costs[i] / l + costs[i+l] / l 18 | min_ave = min(tmp, min_ave) 19 | 20 | return min_ave 21 | 22 | 23 | for _ in range(C): 24 | N, L = (int(x) for x in input().split()) 25 | costs = [int(x) for x in input().split()] 26 | min_avg = get_min_avg(N, L, costs) 27 | 28 | min_lists.append(min_ave) 29 | -------------------------------------------------------------------------------- /problems_solving/algospot/routing.py: -------------------------------------------------------------------------------- 1 | """Get minimal amplified noise in the route 2 | 3 | :input: 4 | 1 5 | 7 14 6 | 0 1 1.3 7 | 0 2 1.1 8 | 0 3 1.24 9 | 3 4 1.17 10 | 3 5 1.24 11 | 3 1 2 12 | 1 2 1.31 13 | 1 2 1.26 14 | 1 4 1.11 15 | 1 5 1.37 16 | 5 4 1.24 17 | 4 6 1.77 18 | 5 6 1.11 19 | 2 6 1.2 20 | 21 | :return: 22 | 1.3200000000 23 | 24 | url: https://algospot.com/judge/problem/read/ROUTING 25 | ID : ROUTING 26 | """ 27 | from heapq import heappop, heappush 28 | from math import inf, log10 29 | from sys import stdin 30 | 31 | get_input = stdin.readline 32 | 33 | 34 | def minimal_noise(g): 35 | V = len(g) 36 | dist = [inf] * V 37 | dist[0] = log10(1) 38 | visited = [False] * V 39 | 40 | while True: 41 | min_dist = inf 42 | here = None 43 | 44 | for v in range(V): 45 | if dist[v] < min_dist and not visited[v]: 46 | here = v 47 | min_dist = dist[v] 48 | 49 | if min_dist == inf: 50 | break 51 | 52 | visited[here] = True 53 | 54 | for cost, there in g[here]: 55 | if visited[there]: 56 | continue 57 | nxt_dist = dist[here] + cost 58 | dist[there] = min(dist[there], nxt_dist) 59 | 60 | return 10 ** dist[V-1] 61 | 62 | 63 | if __name__ == '__main__': 64 | C = int(get_input().strip()) 65 | ans = [] 66 | 67 | for _ in range(C): 68 | V, E = (int(n) for n in get_input().strip().split()) 69 | g = [[] for _ in range(V)] 70 | for _ in range(E): 71 | line = get_input().strip().split() 72 | f, t, n = int(line[0]), int(line[1]), log10(float(line[2])) 73 | g[f].append((n, t)) 74 | g[t].append((n, f)) 75 | ans.append(minimal_noise(g)) 76 | 77 | for noise in ans: 78 | print(noise) 79 | -------------------------------------------------------------------------------- /problems_solving/algospot/runningmedian.py: -------------------------------------------------------------------------------- 1 | """Get sum of running medians 2 | 3 | :input: 4 | 3 5 | 10 1 0 6 | 10 1 1 7 | 10000 1273 4936 8 | 9 | :return: 10 | 19830 11 | 19850 12 | 2448920 13 | 14 | url: https://algospot.com/judge/problem/read/RUNNINGMEDIAN 15 | ID : RUNNINGMEDIAN 16 | """ 17 | import heapq 18 | 19 | 20 | def sum_medians(N, a, b, D=20090711, seed=1983): 21 | def rng(a, b): 22 | s = seed 23 | while True: 24 | ret = s 25 | s = (s * a + b) % D 26 | yield ret 27 | 28 | number_generator = rng(a, b) 29 | ans = 0 30 | max_heap = [] 31 | min_heap = [] 32 | 33 | for _ in range(N): 34 | n = next(number_generator) 35 | if len(max_heap) == len(min_heap): 36 | heapq.heappush(max_heap, (-n, n)) 37 | else: 38 | heapq.heappush(min_heap, (n, n)) 39 | 40 | if max_heap and min_heap and min_heap[0][1] < max_heap[0][1]: 41 | a = heapq.heappop(max_heap)[1] 42 | b = heapq.heappop(min_heap)[1] 43 | heapq.heappush(max_heap, (-b, b)) 44 | heapq.heappush(min_heap, (a, a)) 45 | ans = (ans + max_heap[0][1]) % D 46 | return ans 47 | 48 | 49 | if __name__ == '__main__': 50 | C = int(input()) 51 | ans = [] 52 | for _ in range(C): 53 | N, a, b = (int(n) for n in input().split()) 54 | ans.append(sum_medians(N, a, b)) 55 | 56 | for n in ans: 57 | print(n) 58 | -------------------------------------------------------------------------------- /problems_solving/algospot/snail.py: -------------------------------------------------------------------------------- 1 | """Get the possiblity of snail can reach D meters in N day 2 | 3 | 4 | :input: 5 | 4 6 | 5 4 7 | 5 3 8 | 4 2 9 | 3 2 10 | 11 | :return: 12 | 0.9960937500 13 | 0.8437500000 14 | 0.5625000000 15 | 0.9375000000 16 | 17 | 18 | ID : SNAIL 19 | url: https://algospot.com/judge/problem/read/SNAIL 20 | """ 21 | def can_climb(d, n): 22 | cache = [[-1 for _ in range(d*2+1)] for _ in range(n)] 23 | 24 | def climb(days, climbed): 25 | if days == n: 26 | return 1 if climbed >= d else 0 27 | if cache[days][climbed] != -1: 28 | return cache[days][climbed] 29 | cache[days][climbed] = 0.75 * climb(days+1, climbed+2) \ 30 | + 0.25 * climb(days+1, climbed+1) 31 | return cache[days][climbed] 32 | 33 | return climb(0, 0) 34 | 35 | 36 | if __name__ == '__main__': 37 | N = int(input()) 38 | ans = [] 39 | for _ in range(N): 40 | d, n = (int(x) for x in input().split()) 41 | ans.append(can_climb(d, n)) 42 | 43 | for n in ans: 44 | print(n) 45 | -------------------------------------------------------------------------------- /problems_solving/algospot/strjoin.py: -------------------------------------------------------------------------------- 1 | """Get minimum cost of concatenating files 2 | 3 | :input: 4 | 3 5 | 3 6 | 2 2 4 7 | 5 8 | 3 1 3 4 1 9 | 8 10 | 1 1 1 1 1 1 1 2 11 | 12 | :return: 13 | 12 14 | 26 15 | 27 16 | 17 | url: https://algospot.com/judge/problem/read/STRJOIN 18 | ID : STRJOIN 19 | """ 20 | def strjoin(lens): 21 | ret = 0 22 | lens.sort() 23 | 24 | while len(lens) > 1: 25 | a = lens.pop(0) 26 | b = lens.pop(0) 27 | ret += a + b 28 | lens.append(a + b) 29 | lens.sort() 30 | return ret 31 | 32 | 33 | if __name__ == '__main__': 34 | C = int(input()) 35 | ans = [] 36 | for _ in range(C): 37 | N = int(input()) 38 | lengths = [int(n) for n in input().split()] 39 | ans.append(strjoin(lengths)) 40 | 41 | for n in ans: 42 | print(n) 43 | -------------------------------------------------------------------------------- /problems_solving/algospot/sushi.py: -------------------------------------------------------------------------------- 1 | """Get maximum utilities of eating sushi in given budget 2 | 3 | :input: 4 | 2 5 | 6 10000 6 | 2500 7 7 | 3000 9 8 | 4000 10 9 | 5000 12 10 | 10000 20 11 | 15000 1 12 | 6 543975612 13 | 2500 7 14 | 3000 9 15 | 4000 10 16 | 5000 12 17 | 10000 20 18 | 15000 1 19 | 20 | :return: 21 | 28 22 | 1631925 23 | 24 | ID : SUSHI 25 | url: https://algospot.com/judge/problem/read/SUSHI 26 | """ 27 | def max_utility(budget, prices, prefs): 28 | budget //= 100 29 | prices = [p // 100 for p in prices] 30 | ret = 0 31 | cache = [0 for _ in range(20000 // 100+1)] 32 | item_length = len(prices) 33 | 34 | for b in range(1, budget+1): 35 | cand = 0 36 | for dish in range(item_length): 37 | if b >= prices[dish]: 38 | cand = max(cand, cache[(b-prices[dish]) % 201] + prefs[dish]) 39 | cache[b % 201] = cand 40 | ret = max(ret, cand) 41 | return ret 42 | 43 | 44 | if __name__ == '__main__': 45 | C = int(input()) 46 | ans = [] 47 | for _ in range(C): 48 | prices = [] 49 | prefs = [] 50 | N, budget = (int(n) for n in input().split()) 51 | 52 | for _ in range(N): 53 | p, f = (int(n) for n in input().split()) 54 | prices.append(p) 55 | prefs.append(f) 56 | 57 | ans.append(max_utility(budget, prices, prefs)) 58 | 59 | for n in ans: 60 | print(n) 61 | -------------------------------------------------------------------------------- /problems_solving/algospot/test: -------------------------------------------------------------------------------- 1 | 3 2 | 4 3 | 1 2 3 4 4 | 8 5 | 5 4 3 2 1 6 7 8 6 | 8 7 | 5 6 7 8 1 2 3 4 8 | -------------------------------------------------------------------------------- /problems_solving/algospot/tiling2.py: -------------------------------------------------------------------------------- 1 | """Get the number of cases of ways to cover all the board 2 | 3 | Get the answer of mod by 1000000007 4 | 5 | :input: 6 | 3 7 | 1 8 | 5 9 | 100 10 | 11 | :output: 12 | 1 13 | 8 14 | 782204094 15 | 16 | ID : TILING2 17 | url: https://algospot.com/judge/problem/read/TILING2 18 | """ 19 | def get_tile_ways(n): 20 | if n == 1: 21 | return 1 22 | 23 | cache = [-1 for _ in range(n+1)] 24 | cache[1] = 1 25 | cache[2] = 2 26 | 27 | def iterate(n): 28 | if cache[n] != -1: 29 | return cache[n] 30 | cache[n] = iterate(n-1) + iterate(n-2) 31 | cache[n] %= 1000000007 32 | return cache[n] 33 | 34 | return iterate(n) 35 | 36 | 37 | C = int(input()) 38 | ans = [] 39 | for _ in range(C): 40 | ans.append(get_tile_ways(int(input()))) 41 | 42 | for n in ans: 43 | print(n) 44 | -------------------------------------------------------------------------------- /problems_solving/algospot/traversal.py: -------------------------------------------------------------------------------- 1 | """Return result of postorder traversal of binary tree 2 | 3 | :input: 4 | 2 5 | 7 6 | 27 16 9 12 54 36 72 7 | 9 12 16 27 36 54 72 8 | 6 9 | 409 479 10 838 150 441 10 | 409 10 479 150 838 441 11 | 12 | :return: 13 | 12 9 16 36 72 54 27 14 | 10 150 441 838 479 409 15 | 16 | url: https://algospot.com/judge/problem/read/TRAVERSAL 17 | ID : TRAVERSAL 18 | """ 19 | def make_post(preorder, inorder): 20 | N = len(preorder) 21 | if not preorder: 22 | return 23 | root = preorder[0] 24 | 25 | L = 0 26 | while L < N: 27 | if inorder[L] == root: 28 | break 29 | L += 1 30 | 31 | make_post(preorder[1:L+1], inorder[:L]) 32 | make_post(preorder[L+1:], inorder[L+1:]) 33 | 34 | print(root, end=' ') 35 | 36 | 37 | if __name__ == '__main__': 38 | C = int(input()) 39 | ans = [] 40 | for _ in range(C): 41 | N = int(input()) 42 | preorder = [int(n) for n in input().split()] 43 | inorder = [int(n) for n in input().split()] 44 | make_post(preorder, inorder) 45 | print() 46 | -------------------------------------------------------------------------------- /problems_solving/algospot/trianglepath.py: -------------------------------------------------------------------------------- 1 | """Get the max sum of all possible paths in a triangle 2 | 3 | 4 | url: https://algospot.com/judge/problem/read/TRIANGLEPATH 5 | ID : TRIANGLEPATH 6 | """ 7 | def max_path_sum(triangle): 8 | length = len(triangle) 9 | cache = [[-1 for _ in range(length)] for _ in range(length)] 10 | 11 | def sub_sum(y, x): 12 | if y == length - 1: 13 | return triangle[y][x] 14 | elif cache[y][x] != -1: 15 | return cache[y][x] 16 | else: 17 | cache[y][x] = max(sub_sum(y+1, x), sub_sum(y+1, x+1)) + triangle[y][x] 18 | return cache[y][x] 19 | 20 | return sub_sum(0, 0) 21 | 22 | 23 | C = int(input()) 24 | ans = [] 25 | for _ in range(C): 26 | N = int(input()) 27 | triangle = [] 28 | for _ in range(N): 29 | triangle.append([int(x) for x in input().split()]) 30 | ans.append(max_path_sum(triangle)) 31 | 32 | 33 | for n in ans: 34 | print(n) 35 | -------------------------------------------------------------------------------- /problems_solving/algospot/tripathcnt.py: -------------------------------------------------------------------------------- 1 | """Return the number of paths that maximize the total sum of their elements 2 | 3 | :input: 4 | 2 5 | 4 6 | 1 7 | 1 1 8 | 1 1 1 9 | 1 1 1 1 10 | 4 11 | 9 12 | 5 7 13 | 1 3 2 14 | 3 5 5 6 15 | 16 | :return: 17 | 8 18 | 3 19 | 20 | ID : TRIPATHCNT 21 | url: https://algospot.com/judge/problem/read/TRIPATHCNT 22 | """ 23 | def path_count(tri): 24 | length = len(tri) 25 | cache = [[-1 for _ in range(length)] for _ in range(length)] 26 | count_cache = [[-1 for _ in range(length)] for _ in range(length)] 27 | 28 | def find(y, x): 29 | if y == length - 1: 30 | return tri[y][x] 31 | elif cache[y][x] != -1: 32 | return cache[y][x] 33 | else: 34 | cache[y][x] = max(find(y+1, x), find(y+1, x+1)) + tri[y][x] 35 | return cache[y][x] 36 | 37 | def count(y, x): 38 | if y == length - 1: 39 | return 1 40 | elif count_cache[y][x] != -1: 41 | return count_cache[y][x] 42 | else: 43 | ret = 0 44 | if find(y+1, x+1) >= find(y+1, x): 45 | ret += count(y+1, x+1) 46 | if find(y+1, x+1) <= find(y+1, x): 47 | ret += count(y+1, x) 48 | count_cache[y][x] = ret 49 | return ret 50 | return count(0, 0) 51 | 52 | 53 | 54 | if __name__ == '__main__': 55 | C = int(input()) 56 | ans = [] 57 | for _ in range(C): 58 | N = int(input()) 59 | tri = [] 60 | for _ in range(N): 61 | tri.append([int(n) for n in input().split()]) 62 | ans.append(path_count(tri)) 63 | 64 | for n in ans: 65 | print(n) 66 | -------------------------------------------------------------------------------- /problems_solving/algospot/wildcard.py: -------------------------------------------------------------------------------- 1 | """Check if wildcard pattern matches the given string 2 | 3 | 4 | ID: WILDCARD 5 | 6 | 7 | https://algospot.com/judge/problem/read/WILDCARD 8 | """ 9 | 10 | # exhaustive search 11 | def exhaustive_match(pattern: str, string: str): 12 | pos = 0 13 | while pos < len(pattern) and pos < len(string) and \ 14 | (pattern[pos] == '?' or pattern[pos] == string[pos]): 15 | pos += 1 16 | 17 | if pos == len(pattern): 18 | return True if pos == len(string) else False 19 | 20 | if pattern[pos] == '*': 21 | skip = 0 22 | while skip + pos <= len(string): 23 | if exhaustive_match(pattern[pos+1:], string[pos+skip:]): 24 | return True 25 | skip += 1 26 | 27 | return False 28 | 29 | 30 | # memoization 31 | def memoized_match(pattern, word): 32 | len_p, len_w = len(pattern), len(word) 33 | cache = [[-1 for _ in range(len_w+1)] for _ in range(len_p+1)] 34 | def match(pp, wp): 35 | if cache[pp][wp] != -1: 36 | return cache[pp][wp] 37 | 38 | if pp < len_p and wp < len_w and (pattern[pp] == '?' or pattern[pp] == word[wp]): 39 | cache[pp][wp] = match(pp+1, wp+1) 40 | return cache[pp][wp] 41 | 42 | if pp == len_p: 43 | cache[pp][wp] = (wp == len_p) 44 | return cache[pp][wp] 45 | 46 | if pattern[pp] == '*': 47 | if match(pp+1, wp) or (wp < len_w and match(pp, wp+1)): 48 | cache[pp][wp] = True 49 | return True 50 | 51 | cache[pp][wp] = False 52 | return False 53 | 54 | return match(0, 0) 55 | -------------------------------------------------------------------------------- /problems_solving/algospot/zimbabwe.py: -------------------------------------------------------------------------------- 1 | """Return number of cases of anagrams of a number that can be divided by given m 2 | 3 | :input: 4 | 4 5 | 321 3 6 | 123 3 7 | 422 2 8 | 12738173912 7 9 | 10 | :return: 11 | 5 12 | 0 13 | 2 14 | 11033 15 | 16 | url: https://algospot.com/judge/problem/read/ZIMBABWE 17 | ID : ZIMBABWE 18 | """ 19 | def zimbabwe(e, m, MOD=None): 20 | e = str(e) 21 | sorted_str = ''.join(sorted(e)) 22 | N = len(sorted_str) 23 | cache = [[[-1 for _ in range(2)] for _ in range(m)] for _ in range(1< 0 and sorted_str[nxt-1] == sorted_str[nxt] and (taken & (1<<(nxt-1))) == 0: 37 | continue 38 | 39 | nxt_taken = taken | (1< sorted_str[nxt] 42 | ret += price(index+1, nxt_taken, nxt_mod, nxt_less) 43 | if MOD: 44 | ret %= MOD 45 | 46 | cache[taken][mod][less] = ret 47 | return ret 48 | 49 | return price(0, 0, 0, 0) 50 | 51 | 52 | if __name__ == '__main__': 53 | C = int(input()) 54 | ans = [] 55 | 56 | for _ in range(C): 57 | e, m = (int(n) for n in input().split()) 58 | ans.append(zimbabwe(e, m, int(1e9)+7)) 59 | 60 | for n in ans: 61 | print(n) 62 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/acm_craft.py: -------------------------------------------------------------------------------- 1 | """Get the mininum cost of building a wanted building 2 | 3 | 4 | url: https://www.acmicpc.net/problem/1005 5 | """ 6 | import sys 7 | sys.setrecursionlimit(10 ** 9) 8 | 9 | 10 | def get_building_time(w, time, rule_cache): 11 | total_time_cache = [-1 for _ in range(len(time))] 12 | 13 | for i in rule_cache[0]: 14 | total_time_cache[i] = time[i] 15 | 16 | def get_time(w): 17 | if total_time_cache[w] == -1: 18 | ret = -1 19 | for src in rule_cache[w]: 20 | ret = max(ret, get_time(src)) 21 | total_time_cache[w] = ret + time[w] 22 | return total_time_cache[w] 23 | return get_time(w) 24 | 25 | 26 | if __name__ == '__main__': 27 | C = int(input()) 28 | ans = [] 29 | 30 | for _ in range(C): 31 | N, R = (int(n) for n in input().split()) 32 | time = [0] + [int(n) for n in input().split()] 33 | rule_cache = [[] for _ in range(len(time))] 34 | start = [1 for _ in range(len(time))] 35 | 36 | for _ in range(R): 37 | src, dest = (int(n) for n in input().split()) 38 | rule_cache[dest].append(src) 39 | start[dest] = 0 40 | rule_cache[0] = [dest for dest in range(len(time)) if start[dest] == 1] 41 | 42 | 43 | W = int(input()) 44 | v = get_building_time(W, time, rule_cache) 45 | ans.append(v) 46 | 47 | for n in ans: 48 | print(n) 49 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/balanced_world.py: -------------------------------------------------------------------------------- 1 | """Return if braces in strings are valid or not for each sentence 2 | 3 | :input: 4 | So when I die (the [first] I will see in (heaven) is a score list). 5 | [ first in ] ( first out ). 6 | Half Moon tonight (At least it is better than no Moon at all]. 7 | A rope may form )( a trail in a maze. 8 | Help( I[m being held prisoner in a fortune cookie factory)]. 9 | ([ (([( [ ] ) ( ) (( ))] )) ]). 10 | . 11 | . 12 | 13 | :return: 14 | yes 15 | yes 16 | no 17 | no 18 | no 19 | yes 20 | yes 21 | 22 | URL: https://www.acmicpc.net/problem/4949 23 | ID : 4949 24 | """ 25 | def is_valid_string(strng): 26 | OPENING = '([' 27 | CLOSING = ')]' 28 | 29 | opener_stack = [] 30 | for c in strng: 31 | if c in OPENING: 32 | opener_stack.append(c) 33 | elif c in CLOSING: 34 | if not opener_stack: 35 | return False 36 | o = opener_stack.pop() 37 | if OPENING.index(o) != CLOSING.index(c): 38 | return False 39 | 40 | return False if opener_stack else True 41 | 42 | 43 | if __name__ == '__main__': 44 | while True: 45 | strng = input() 46 | if strng == '.': 47 | break 48 | else: 49 | print('yes' if is_valid_string(strng) else 'no') 50 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/bertran_postulate.py: -------------------------------------------------------------------------------- 1 | """Return number of primes between (n, 2n] when a natural number n is given 2 | 3 | :input: 4 | 1 5 | 10 6 | 13 7 | 100 8 | 1000 9 | 10000 10 | 100000 11 | 0 12 | 13 | :return: 14 | 1 15 | 4 16 | 3 17 | 21 18 | 135 19 | 1033 20 | 8392 21 | """ 22 | SIZE = 123456 * 2 + 1 23 | SQRT_SIZE = int(SIZE ** (1/2)) 24 | 25 | sieves = [1 for _ in range(SIZE+1)] 26 | sieves[0] = sieves[1] = 0 27 | cum_count_prime = [0 for _ in range(SIZE+1)] 28 | 29 | 30 | for n in range(2, SIZE+1): 31 | cum_count_prime[n] = cum_count_prime[n-1] 32 | if sieves[n] == 1: 33 | for j in range(n*n, SIZE+1, n): 34 | sieves[j] = 0 35 | 36 | cum_count_prime[n] += 1 37 | 38 | 39 | 40 | if __name__ == '__main__': 41 | wanted = [] 42 | while True: 43 | n = int(input()) 44 | if n != 0: 45 | wanted.append(n) 46 | else: 47 | break 48 | 49 | for n in wanted: 50 | print(cum_count_prime[2*n] - cum_count_prime[n]) 51 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/cardgame.py: -------------------------------------------------------------------------------- 1 | """Return Geun-u's maximum score 2 | 3 | :input: 4 | 2 5 | 4 6 | 1 2 5 2 7 | 9 8 | 1 1 1 1 2 2 2 2 2 9 | 10 | :return: 11 | 6 12 | 8 13 | 14 | ID : 11062 15 | url: https://www.acmicpc.net/problem/11062 16 | """ 17 | import sys 18 | sys.setrecursionlimit(10 ** 8) 19 | 20 | 21 | def get_score(l): 22 | N = len(l) 23 | cache = [[-1 for _ in range(N)] for _ in range(N)] 24 | 25 | def get(lo, hi, turn): 26 | if lo > hi: 27 | return 0 28 | elif cache[lo][hi] != -1: 29 | return cache[lo][hi] 30 | 31 | if turn == 1: 32 | ret = max(get(lo+1, hi, 1-turn) + l[lo], 33 | get(lo, hi-1, 1-turn) + l[hi]) 34 | else: 35 | ret = min(get(lo+1, hi, 1-turn), 36 | get(lo, hi-1, 1-turn)) 37 | cache[lo][hi] = ret 38 | return ret 39 | return get(0, N-1, 1) 40 | 41 | 42 | if __name__ == '__main__': 43 | C = int(input()) 44 | ans = [] 45 | for _ in range(C): 46 | input() 47 | l = [int(n) for n in input().split()] 48 | ans.append(get_score(l)) 49 | for n in ans: 50 | print(n) 51 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/dance_dance_revolution_2342.py: -------------------------------------------------------------------------------- 1 | """Get minimum cost of playing DDR game 2 | 3 | :input: 4 | 1 2 2 4 0 5 | 6 | :return: 7 | 8 8 | 9 | url: https://www.acmicpc.net/problem/2342 10 | """ 11 | import sys 12 | 13 | 14 | INF = 987654321 15 | 16 | 17 | def move_cost(prev, nxt): 18 | diff = abs(prev - nxt) 19 | if diff == 0: 20 | return 1 21 | elif prev == 0 and nxt != 0: 22 | return 2 23 | elif prev != 0 and nxt == 0: 24 | return 0 25 | elif diff == 1 or diff == 3: 26 | return 3 27 | else: 28 | return 4 29 | 30 | 31 | def count(l, r, n): 32 | if l == r and n != 0: 33 | return INF 34 | elif n == N: 35 | return 0 36 | elif cache[l][r][n] != -1: 37 | return cache[l][r][n] 38 | ret = INF 39 | ret = min(ret, 40 | count(arr[n+1], r, n+1) + move_cost(l, arr[n+1]), 41 | count(l, arr[n+1], n+1) + move_cost(r, arr[n+1]) 42 | ) 43 | cache[l][r][n] = ret 44 | return ret 45 | 46 | 47 | if __name__ == '__main__': 48 | sys.setrecursionlimit(10**8) 49 | 50 | arr = [0] + [int(n) for n in input().split()][:-1] 51 | N = len(arr) 52 | arr.append(0) 53 | cache = [[[-1 for _ in range(N+1)] for _ in range(5)] \ 54 | for _ in range(5)] 55 | 56 | print(count(0, 0, 0)) 57 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/data: -------------------------------------------------------------------------------- 1 | 5 2 | okpo sacheon hansan myeongnyang noryang 3 | sacheon hansan myeongnyang noryang okpo 4 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/decreasing_number.py: -------------------------------------------------------------------------------- 1 | def desc_n(n): 2 | skip = n 3 | ans = [] 4 | 5 | def find(chosen, d): 6 | nonlocal ans, skip 7 | 8 | if skip < 0: 9 | return 10 | if len(chosen) == d: 11 | if skip == 0: 12 | ans = chosen.copy() 13 | skip -= 1 14 | return 15 | 16 | last = chosen[-1] 17 | for j in range(last): 18 | chosen.append(j) 19 | find(chosen, d) 20 | chosen.pop() 21 | 22 | for d in range(1, 11): 23 | for i in range(10): 24 | find([i], d) 25 | if skip < 0: 26 | break 27 | 28 | return ans 29 | 30 | 31 | print(''.join([str(n) for n in ans]) if ans else '-1') 32 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/evaluate_parenthesis.py: -------------------------------------------------------------------------------- 1 | """Return value of the evaluated parenthesis expression 2 | 3 | :input: 4 | (()[[]])([]) 5 | 6 | :return: 7 | 28 8 | 9 | url: https://www.acmicpc.net/problem/2504 10 | """ 11 | expression = input() 12 | OPENS = '([' 13 | CLOSES = ')]' 14 | 15 | def evaluate(expression): 16 | stack = [] 17 | total = 0 18 | flags = [0, 0] 19 | 20 | for i, c in enumerate(expression): 21 | if c in OPENS: 22 | stack.append(c) 23 | flags[OPENS.index(c)] += 1 24 | else: 25 | flags[CLOSES.index(c)] -= 1 26 | if flags[CLOSES.index(c)] < 0: 27 | return 0 28 | 29 | num = 0 30 | op = stack.pop() 31 | while isinstance(op, int): 32 | num += op 33 | op = stack.pop() 34 | 35 | if OPENS.index(op) != CLOSES.index(c): 36 | return 0 37 | 38 | num = num if num else 1 39 | stack.append(num * (OPENS.index(op)+2)) 40 | 41 | while stack: 42 | popped = stack.pop() 43 | if not isinstance(popped, int): 44 | return 0 45 | total += popped 46 | return total 47 | 48 | 49 | print(evaluate(expression)) 50 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/find_parent_in_tree.py: -------------------------------------------------------------------------------- 1 | """Find parent nodes of all nodes in a tree 2 | :input: 3 | 7 4 | 1 6 5 | 6 3 6 | 3 5 7 | 4 1 8 | 2 4 9 | 4 7 10 | 11 | :return: 12 | 4 13 | 6 14 | 1 15 | 3 16 | 1 17 | 4 18 | 19 | url: https://www.acmicpc.net/problem/11725 20 | """ 21 | from sys import stdin 22 | 23 | 24 | N = int(input()) 25 | parent = [None] * (N+1) 26 | parent[1] = 0 27 | visited = [0] * (N+1) 28 | visited[1] = 1 29 | queue = [1] 30 | relations = [[] for _ in range(N+1)] 31 | 32 | 33 | for _ in range(N-1): 34 | a, b = (int(n) for n in stdin.readline().strip().split()) 35 | relations[a].append(b) 36 | relations[b].append(a) 37 | 38 | 39 | while queue: 40 | x = queue.pop() 41 | for child in relations[x]: 42 | if not visited[child]: 43 | visited[child] = 1 44 | queue.append(child) 45 | parent[child] = x 46 | 47 | 48 | for i in range(2, N+1): 49 | print(parent[i]) 50 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/goldbach_conjecture.py: -------------------------------------------------------------------------------- 1 | """Return a tuple of 2 prime numbers which consist of given N 2 | 3 | :input: 4 | 3 5 | 8 6 | 10 7 | 16 8 | 9 | :return: 10 | 3 5 11 | 5 5 12 | 5 11 13 | 14 | url: https://www.acmicpc.net/problem/9020 15 | """ 16 | SIZE = 10000 17 | sieves = [1 for _ in range(SIZE + 1)] 18 | sieves[0] = sieves[1] = 0 19 | 20 | for i in range(2, int(SIZE ** (1/2))): 21 | if sieves[i] == 1: 22 | for j in range(i*i, SIZE+1, i): 23 | sieves[j] = 0 24 | 25 | 26 | def prime_pair(n): 27 | if n == 4: 28 | return 2, 2 29 | 30 | half = n // 2 31 | lo, hi = (half - 1, half + 1) if half % 2 == 0 else (half, half) 32 | while lo > 1: 33 | if sieves[lo] == 1 and sieves[hi] == 1: 34 | return lo, hi 35 | lo -= 2 36 | hi += 2 37 | 38 | 39 | if __name__ == '__main__': 40 | C = int(input()) 41 | ans = [] 42 | for _ in range(C): 43 | n = int(input()) 44 | ans.append(prime_pair(n)) 45 | 46 | for n in ans: 47 | print(' '.join(str(i) for i in n)) 48 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/henry.py: -------------------------------------------------------------------------------- 1 | """Get denominator of last element of henry expression 2 | 3 | :input: 4 | 3 5 | 4 23 6 | 5 7 7 | 8 11 8 | 9 | :return: 10 | 138 11 | 70 12 | 4070 13 | 14 | url: https://www.acmicpc.net/problem/10253 15 | """ 16 | def gcd(a, b): 17 | return a if b == 0 else gcd(b, a % b) 18 | 19 | 20 | def get_last_denominator(a, b): 21 | while a != 1: 22 | denom = int(b / a + 1) 23 | a = a * denom - b 24 | b *= denom 25 | 26 | a //= gcd(a, b) 27 | b //= gcd(a, b) 28 | 29 | return b 30 | 31 | 32 | if __name__ == '__main__': 33 | C = int(input()) 34 | ans = [] 35 | for _ in range(C): 36 | a, b = (int(n) for n in input().split()) 37 | ans.append(get_last_denominator(a, b)) 38 | 39 | for n in ans: 40 | print(n) 41 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/lcs2.py: -------------------------------------------------------------------------------- 1 | """Get LCS in two sentences 2 | 3 | :input: 4 | ACAYKP 5 | CAPCAK 6 | 7 | :return: 8 | 4 9 | ACAK 10 | 11 | url: https://www.acmicpc.net/problem/9252 12 | """ 13 | def lcs_exhaustive(a, b): 14 | if a == '' or b == '': 15 | return '' 16 | ret = '' 17 | for i in range(len(a)): 18 | for j in range(len(b)): 19 | if a[i] == b[j]: 20 | cand = a[i] + lcs_exhaustive(a[i+1:], b[j+1:]) 21 | ret = ret if len(ret) >= len(cand) else cand 22 | return ret 23 | 24 | 25 | def lcs(a, b): 26 | a = ' ' + a 27 | b = ' ' + b 28 | cache = [[0 for _ in range(len(b))] for _ in range(len(a))] 29 | lcs_cache = [['' for _ in range(len(b))] for _ in range(len(a))] 30 | 31 | for i in range(1, len(a)): 32 | for j in range(1, len(b)): 33 | if a[i] == b[j]: 34 | cache[i][j] = cache[i-1][j-1] + 1 35 | lcs_cache[i][j] = lcs_cache[i-1][j-1] + a[i] 36 | elif cache[i-1][j] > cache[i][j-1]: 37 | cache[i][j] = cache[i-1][j] 38 | lcs_cache[i][j] = lcs_cache[i-1][j] 39 | else: 40 | cache[i][j] = cache[i][j-1] 41 | lcs_cache[i][j] = lcs_cache[i][j-1] 42 | return lcs_cache[len(a)-1][len(b)-1] 43 | 44 | 45 | if __name__ == '__main__': 46 | a = input() 47 | b = input() 48 | ans = lcs(a, b) 49 | print(len(ans)) 50 | print(ans) 51 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/lightbulb.py: -------------------------------------------------------------------------------- 1 | """Get minimum number of chaning color of light bulbs until all colors are same 2 | 3 | :input: 4 | 10 3 5 | 1 1 2 3 3 3 2 2 1 1 6 | 7 | :return: 8 | 2 9 | 10 | url: https://www.acmicpc.net/problem/2449 11 | """ 12 | def min_count(arr): 13 | N = len(arr) 14 | cache = [[-1 for _ in range(N)] for _ in range(N)] 15 | 16 | def get(lo, hi): 17 | if lo == hi: 18 | return 0 19 | elif cache[lo][hi] != -1: 20 | return cache[lo][hi] 21 | 22 | if hi > 0 and arr[hi] == arr[hi-1]: 23 | ret = get(lo, hi-1) 24 | elif lo + 1 < N and arr[lo] == arr[lo+1]: 25 | ret = get(lo+1, hi) 26 | else: 27 | ret = 9999 28 | for k in range(lo, hi): 29 | ret = min(ret, get(lo, k) + get(k+1, hi) + (arr[lo] != arr[k+1])) 30 | 31 | cache[lo][hi] = ret 32 | return ret 33 | 34 | return get(0, N-1) 35 | 36 | 37 | if __name__ == '__main__': 38 | N, K = (int(n) for n in input().split()) 39 | arr = [int(n) for n in input().split()] 40 | print(arr) 41 | 42 | print(min_count(arr)) 43 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/make_colored_paper.py: -------------------------------------------------------------------------------- 1 | """Get the numbers of white and blue sub-blocks 2 | 3 | url: https://www.acmicpc.net/problem/2630 4 | """ 5 | def count_white_blue(board): 6 | N = len(board) 7 | WHITE, BLUE = range(2) 8 | 9 | def cut_off(r, c, size): 10 | color = board[r][c] 11 | white = blue = 0 12 | if size == 1: 13 | return (1, 0) if color == WHITE else (0, 1) 14 | elif all(board[r+dr][c+dc] == color for dr in range(size) for dc in range(size)): 15 | return (1, 0) if color == WHITE else (0, 1) 16 | 17 | half_size = size // 2 18 | for dr in range(2): 19 | for dc in range(2): 20 | d_white, d_blue = cut_off(r + dr*half_size, c + dc*half_size, half_size) 21 | white += d_white 22 | blue += d_blue 23 | return white, blue 24 | 25 | return cut_off(0, 0, N) 26 | 27 | 28 | if __name__ == '__main__': 29 | N = int(input()) 30 | board = [] 31 | for _ in range(N): 32 | board.append([int(n) for n in input().split()]) 33 | 34 | white, blue = count_white_blue(board) 35 | print(white) 36 | print(blue) 37 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/make_n_to_1.py: -------------------------------------------------------------------------------- 1 | """Make smallest number of cases to make given N to 1 2 | 3 | There are 3 rules for integer X to adapt. 4 | 5 | 1. if X is divisible by 3, divide it by 3. 6 | 2. if X is divisible by 2, divide it by 2. 7 | 3. Subtract 1. 8 | 9 | When integer N is given, we wanna make it to 1 using 3 commands. 10 | Get the smallest number of cases of it 11 | 12 | 13 | if N = 10, answer is "3" (10 -> 9 -> 3 -> 1) 14 | 15 | url: https://www.acmicpc.net/problem/1463 16 | """ 17 | def make_to_1(n): 18 | cache = [0 for _ in range(n+1)] 19 | for i in range(2, n+1): 20 | tmp = 987654321 21 | cache[i] = min(tmp, cache[i-1]+1) 22 | if i % 2 == 0: 23 | cache[i] = min(cache[i], cache[i//2]+1) 24 | if i % 3 == 0: 25 | cache[i] = min(cache[i], cache[i//3]+1) 26 | return cache[n] 27 | 28 | 29 | if __name__ == '__main__': 30 | N = int(input()) 31 | print(make_to_1(N)) 32 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/matrix_multiplication_order.py: -------------------------------------------------------------------------------- 1 | """Return minimum multiplication counts of series of matrices 2 | 3 | :input: 4 | 3 5 | 5 3 6 | 3 2 7 | 2 6 8 | 9 | :return: 10 | 90 11 | 12 | url: https://www.acmicpc.net/problem/11049 13 | ID : 11049 14 | """ 15 | # 참고로 이 풀이는 pypy3에서만 돌아감... 16 | ANS_LIMIT = 2 ** 32 17 | 18 | 19 | class Matrix: 20 | def __init__(self, r, c): 21 | self.r = r 22 | self.c = c 23 | 24 | 25 | def minimal_counts(dimensions): 26 | N = len(dimensions) 27 | cache = [[None] * N for _ in range(N)] 28 | 29 | def count(a, b): 30 | if b == a: 31 | return 0 32 | elif cache[a][b] is not None: 33 | return cache[a][b] 34 | 35 | tmp_ans = ANS_LIMIT 36 | for k in range(a, b): 37 | tmp_ans = min(tmp_ans, count(a, k) + count(k+1, b) \ 38 | + dimensions[a].r * dimensions[k].c * dimensions[b].c) 39 | cache[a][b] = tmp_ans 40 | return tmp_ans 41 | return count(0, N-1) 42 | 43 | 44 | if __name__ == '__main__': 45 | C = int(input()) 46 | dimensions = [] 47 | for i in range(C): 48 | r, c = (int(n) for n in input().split()) 49 | dimensions.append(Matrix(r, c)) 50 | print(minimal_counts(dimensions)) 51 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/merge_files.py: -------------------------------------------------------------------------------- 1 | """Return the minimum cost of merging chapters into a single file 2 | 3 | :input: 4 | 2 5 | 4 6 | 40 30 30 50 7 | 15 8 | 1 21 3 4 5 35 5 4 3 5 98 21 14 17 32 9 | 10 | :return: 11 | 300 12 | 864 13 | 14 | url : https://www.acmicpc.net/problem/11066 15 | """ 16 | import sys 17 | sys.setrecursionlimit(10 ** 9) 18 | 19 | def min_merge_cost(chaps): 20 | length = len(chaps) 21 | cache = [[-1 for _ in range(length+1)] for _ in range(length+1)] 22 | cache[1][1:length+1] = chaps 23 | sub_sum = [0 for _ in range(length+1)] 24 | for i in range(1, length+1): 25 | sub_sum[i] = sub_sum[i-1] + cache[1][i] 26 | 27 | def merge(r, c): 28 | if cache[r][c] != -1: 29 | return cache[r][c] 30 | ret = 987654321 31 | cost = sub_sum[r+c-1] - sub_sum[c-1] 32 | 33 | for k in range(1, r): 34 | ret = min(ret, merge(k, c) + merge(r-k, c+k)) 35 | cache[r][c] = ret + cost 36 | return cache[r][c] 37 | return merge(length, 1) - sub_sum[length] 38 | 39 | 40 | if __name__ == '__main__': 41 | C = int(input()) 42 | ans = [] 43 | 44 | for _ in range(C): 45 | N = int(input()) 46 | chapters = [int(n) for n in input().split()] 47 | ans.append(min_merge_cost(chapters)) 48 | for n in ans: 49 | print(n) 50 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/multiplication.py: -------------------------------------------------------------------------------- 1 | """Get (A ** B) % C in an effective way 2 | 3 | url: https://www.acmicpc.net/problem/1629 4 | """ 5 | def multiplication(iterable): 6 | A, B, C = iterable 7 | 8 | e = 0 9 | ans = 1 10 | tmp = A % C 11 | 12 | while 2 ** e <= B: 13 | if (2 ** e) & B != 0: 14 | ans = (ans * tmp) % C 15 | 16 | tmp = (tmp * tmp) % C 17 | e += 1 18 | 19 | return ans 20 | 21 | 22 | if __name__ == '__main__': 23 | print(multiplication(int(n) for n in input().split())) 24 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/naval_battle.py: -------------------------------------------------------------------------------- 1 | """Return Ratio of right orders to all pairs 2 | 3 | :input: 4 | 5 5 | okpo sacheon hansan myeongnyang noryang 6 | sacheon hansan myeongnyang noryang okpo 7 | 8 | :return: 9 | 6/10 10 | 11 | :condition: 12 | Do not reduce the ratio. 13 | 14 | url: https://www.acmicpc.net/problem/3077 15 | """ 16 | def get_score(answers, submitted): 17 | N = len(answers) 18 | total_cand = int(N / 2 * (N - 1)) 19 | ans = 0 20 | tmp_arr = [0] * N 21 | 22 | # tmp_arr[i] -> submitted 안에서 answers[i]가 있는 위치 23 | for i in range(N): 24 | target = answers[i] 25 | tmp_arr[i] = submitted.index(target) 26 | 27 | def find(chosen): 28 | nonlocal ans 29 | if len(chosen) == 2: 30 | a, b = chosen 31 | ans += (tmp_arr[a] < tmp_arr[b]) 32 | return 33 | 34 | start = chosen[-1] + 1 if chosen else 0 35 | for nxt in range(start, N): 36 | chosen.append(nxt) 37 | find(chosen) 38 | chosen.pop() 39 | find([]) 40 | return ans, int(total_cand) 41 | 42 | 43 | if __name__ == '__main__': 44 | N = int(input()) 45 | answers = [n for n in input().split()] 46 | submitted = [n for n in input().split()] 47 | n, total = get_score(answers, submitted) 48 | print(n, '/', total, sep='') 49 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1021_circular_queue.py: -------------------------------------------------------------------------------- 1 | """Get least number of calculations to rotate arrays as given 2 | 3 | url: https://www.acmicpc.net/problem/1021 4 | """ 5 | def min_calcs(arr, targets): 6 | """We assume there are no duplicate values in array""" 7 | size = len(arr) 8 | ans = 0 9 | 10 | for t in targets: 11 | k = arr.index(t) 12 | ans += min(k+1, size-k-1) 13 | arr = arr[k+1:] + arr[:k+1] 14 | arr.pop() 15 | size -= 1 16 | 17 | return ans 18 | 19 | 20 | if __name__ == '__main__': 21 | N, _ = (int(n) for n in input().split()) 22 | targets = [int(n) for n in input().split()] 23 | arr = list(range(1, N+1)) 24 | arr = arr[::-1] 25 | print(min_calcs(arr, targets)) 26 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_10816_card_number2.py: -------------------------------------------------------------------------------- 1 | """Get number of each card in deck 2 | 3 | url: https://www.acmicpc.net/problem/10816 4 | """ 5 | from collections import Counter 6 | 7 | 8 | # 1. Using Binary search: O(NlogN + MlogN) 9 | def number_of_cards(arr, target, is_sorted=True): 10 | N = len(arr) 11 | 12 | def get_lower_idx(lo, hi): 13 | if lo == hi: 14 | return lo 15 | 16 | mid = (lo + hi) // 2 17 | if arr[mid] >= target: 18 | return get_lower_idx(lo, mid) 19 | else: 20 | return get_lower_idx(mid+1, hi) 21 | 22 | def get_upper_idx(lo, hi): 23 | if lo == hi: 24 | return lo 25 | 26 | mid = (lo + hi) // 2 + 1 27 | if arr[mid] <= target: 28 | return get_upper_idx(mid, hi) 29 | else: 30 | return get_upper_idx(lo, mid-1) 31 | 32 | 33 | i, j = get_lower_idx(0, N-1), get_upper_idx(0, N-1) 34 | 35 | if arr[i] != target: 36 | return 0 37 | else: 38 | return j - i + 1 39 | 40 | 41 | # 2. Using Hash: O(N + M) 42 | def number_of_cards(arr, targets): 43 | counter = Counter(arr) 44 | ans = [] 45 | 46 | for t in targets: 47 | ans.append(counter[t]) 48 | return ans 49 | 50 | 51 | if __name__ == '__main__': 52 | input() 53 | arr = [int(n) for n in input().split()] 54 | # arr.sort() 55 | input() 56 | targets = [int(n) for n in input().split()] 57 | 58 | # 여기서는 해쉬 자료구조로 통과하자. 파이썬으로는 이진탐색으로 안 된다... 59 | print(' '.join(str(n) for n in number_of_cards(arr, targets))) 60 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_10866_deck.py: -------------------------------------------------------------------------------- 1 | """Implement custom deck data structure 2 | 3 | url: https://www.acmicpc.net/problem/10866 4 | """ 5 | from collections import deque 6 | import sys 7 | 8 | input = sys.stdin.readline 9 | 10 | 11 | class Deque: 12 | EMPTY_MESSAGE = -1 13 | 14 | def __init__(self): 15 | self._deque = deque([]) 16 | 17 | def back(self): 18 | return self._deque[-1] if not self.empty() else self.EMPTY_MESSAGE 19 | 20 | def empty(self): 21 | return 1 if self.size() == 0 else 0 22 | 23 | def front(self): 24 | return self._deque[0] if not self.empty() else self.EMPTY_MESSAGE 25 | 26 | def pop_front(self): 27 | return self._deque.popleft() if not self.empty() else self.EMPTY_MESSAGE 28 | 29 | def pop_back(self): 30 | return self._deque.pop() if not self.empty() else self.EMPTY_MESSAGE 31 | 32 | def push_back(self, v): 33 | v = int(v) 34 | self._deque.append(v) 35 | 36 | def push_front(self, v): 37 | v = int(v) 38 | self._deque.appendleft(v) 39 | 40 | def size(self): 41 | return len(self._deque) 42 | 43 | 44 | if __name__ == '__main__': 45 | deck = Deque() 46 | N = int(input()) 47 | 48 | for _ in range(N): 49 | cmd = input().strip().split() 50 | cmd.append('') 51 | 52 | v = eval('deck.' + cmd[0] + '(' + cmd[1] + ')') 53 | if v is not None: 54 | print(v) 55 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_11279_max_heap.py: -------------------------------------------------------------------------------- 1 | """Implement max heap 2 | 3 | url: https://www.acmicpc.net/problem/11279 4 | """ 5 | from heapq import * 6 | import sys 7 | 8 | input = sys.stdin.readline 9 | 10 | 11 | def do_calculations(cmds, min_heap=True): 12 | POPOUT = 0 13 | ret = [] 14 | heap = [] 15 | 16 | for cmd in cmds: 17 | if cmd == POPOUT: 18 | if not heap: 19 | ret.append(0) 20 | else: 21 | _, value = heappop(heap) 22 | ret.append(value) 23 | else: 24 | priority = cmd if min_heap else -cmd 25 | heappush(heap, (priority, cmd)) 26 | 27 | return ret 28 | 29 | 30 | if __name__ == '__main__': 31 | N = int(input()) 32 | cmds = [] 33 | 34 | for _ in range(N): 35 | cmds.append(int(input().strip())) 36 | 37 | for r in do_calculations(cmds, min_heap=False): 38 | print(r) 39 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_11286_absolute_heap.py: -------------------------------------------------------------------------------- 1 | """Implement Absolute heap 2 | 3 | url: https://www.acmicpc.net/problem/11286 4 | """ 5 | from heapq import heappop, heappush 6 | import sys 7 | 8 | input = sys.stdin.readline 9 | 10 | 11 | POPOUT = 0 12 | 13 | 14 | if __name__ == '__main__': 15 | heap = [] 16 | N = int(input()) 17 | 18 | for _ in range(N): 19 | n = int(input()) 20 | if n != POPOUT: 21 | heappush(heap, (abs(n), n)) 22 | else: 23 | if heap: 24 | _, v = heappop(heap) 25 | print(v) 26 | else: 27 | print(0) 28 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_11723_set.py: -------------------------------------------------------------------------------- 1 | """Implement bit set in Python 2 | 3 | url: https://www.acmicpc.net/problem/11723 4 | """ 5 | import sys 6 | 7 | input = sys.stdin.readline 8 | 9 | 10 | class BitSet: 11 | def __init__(self, size): 12 | self._set = 0 13 | self._size = size 14 | 15 | def add(self, v): 16 | self._set |= (1 << v) 17 | 18 | def has(self, n): 19 | return 1 if self._set & (1 << n) else 0 20 | 21 | def remove(self, n): 22 | self._set &= ~(1 << n) 23 | 24 | def toggle(self, n): 25 | self._set ^= (1 << n) 26 | 27 | def turn_on_all(self): 28 | self._set = (1 << (self._size+1)) - 1 29 | 30 | def turn_off_all(self): 31 | self._set >>= (self._size + 1) 32 | 33 | 34 | if __name__ == '__main__': 35 | N = int(input()) 36 | bit_set = BitSet(20) 37 | 38 | for _ in range(N): 39 | cmd, *v = input().strip().split() 40 | if v: 41 | v = int(v[0]) 42 | 43 | if cmd == 'add': 44 | bit_set.add(v) 45 | elif cmd == 'check': 46 | print(bit_set.has(v)) 47 | elif cmd == 'remove': 48 | bit_set.remove(v) 49 | elif cmd == 'toggle': 50 | bit_set.toggle(v) 51 | elif cmd == 'all': 52 | bit_set.turn_on_all() 53 | elif cmd == 'empty': 54 | bit_set.turn_off_all() 55 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_12015_length_of_lis.py: -------------------------------------------------------------------------------- 1 | """Get length of LIS in a sequence 2 | 3 | url: https://www.acmicpc.net/problem/12015 4 | """ 5 | def length_of_lis(arr): 6 | tmp_lis = [] 7 | length = 0 8 | 9 | for n in arr: 10 | if not tmp_lis or tmp_lis[-1] < n: 11 | tmp_lis.append(n) 12 | length += 1 13 | else: 14 | lo, hi = 0, length - 1 15 | while lo < hi: 16 | mid = (lo + hi) // 2 17 | if n <= tmp_lis[mid]: 18 | hi = mid 19 | else: 20 | lo = mid + 1 21 | 22 | tmp_lis[lo] = n 23 | 24 | return length 25 | 26 | 27 | if __name__ == '__main__': 28 | input() 29 | arr = [int(n) for n in input().split()] 30 | print(length_of_lis(arr)) 31 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_12852_change_it_to_1_2.py: -------------------------------------------------------------------------------- 1 | """Change a number to 1 and get process of it too 2 | 3 | https://www.acmicpc.net/problem/12852 4 | """ 5 | import sys 6 | 7 | sys.setrecursionlimit(10 ** 6) 8 | 9 | 10 | def make_it_to_1(N): 11 | INF = float('inf') 12 | cache = {1: 0} 13 | routes = [] 14 | 15 | def min_cost(n): 16 | nonlocal cache 17 | if n in cache: 18 | return cache[n] 19 | 20 | ret = INF 21 | if not n % 2: 22 | ret = min(ret, min_cost(n // 2) + 1) 23 | if not n % 3: 24 | ret = min(ret, min_cost(n // 3) + 1) 25 | if n % 6: 26 | ret = min(ret, min_cost(n-1) + 1) 27 | 28 | cache[n] = ret 29 | return ret 30 | 31 | def trace_route(N): 32 | nonlocal routes 33 | routes.append(N) 34 | if N == 1: 35 | return 36 | 37 | if not N % 3 and min_cost(N) - 1 == min_cost(N // 3): 38 | trace_route(N // 3) 39 | elif not N % 2 and min_cost(N) - 1 == min_cost(N // 2): 40 | trace_route(N // 2) 41 | else: 42 | trace_route(N - 1) 43 | 44 | trace_route(N) 45 | 46 | return min_cost(N), routes 47 | 48 | 49 | if __name__ == '__main__': 50 | N = int(input()) 51 | costs, routes = make_it_to_1(N) 52 | 53 | print(costs) 54 | print(*routes) 55 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1300_kth_number.py: -------------------------------------------------------------------------------- 1 | """Get kth number 2 | 3 | url: https://www.acmicpc.net/problem/1300 4 | """ 5 | def kth_number(N, K): 6 | left, right = 1, K 7 | 8 | while left <= right: 9 | cnt = 0 10 | mid = (left + right) // 2 11 | 12 | for d in range(1, N+1): 13 | cnt += min(mid // d, N) 14 | 15 | if cnt < K: 16 | left = mid + 1 17 | else: 18 | ans = mid 19 | right = mid - 1 20 | 21 | return ans 22 | 23 | 24 | if __name__ == '__main__': 25 | N = int(input()) 26 | K = int(input()) 27 | print(kth_number(N, K)) 28 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_15649_N_and_M_1.py: -------------------------------------------------------------------------------- 1 | """Print out permutations 2 | 3 | https://www.acmicpc.net/problem/15649 4 | """ 5 | import sys 6 | 7 | write = sys.stdout.write 8 | 9 | 10 | def permutations(n, r): 11 | chosen = [] 12 | used = [0] * (n + 1) 13 | 14 | def generate(): 15 | if len(chosen) == r: 16 | for i in range(len(chosen)): 17 | write(str(chosen[i]) + ' ') 18 | write('\n') 19 | return 20 | 21 | for i in range(1, n + 1): 22 | if not used[i]: 23 | chosen.append(i) 24 | used[i] = 1 25 | generate() 26 | chosen.pop() 27 | used[i] = 0 28 | generate() 29 | 30 | 31 | if __name__ == '__main__': 32 | N, R = (int(n) for n in input().split()) 33 | permutations(N, R) 34 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_15650_N_and_M_2.py: -------------------------------------------------------------------------------- 1 | """Print out combinations 2 | 3 | https://www.acmicpc.net/problem/15650 4 | """ 5 | import sys 6 | 7 | write = sys.stdout.write 8 | 9 | 10 | def combinations(n, r): 11 | chosen = [] 12 | used = [0] * (n + 1) 13 | 14 | def generate(): 15 | if len(chosen) == r: 16 | for i in range(len(chosen)): 17 | write(str(chosen[i]) + ' ') 18 | write('\n') 19 | return 20 | 21 | start = chosen[-1] + 1 if chosen else 1 22 | for i in range(start, n+1): 23 | if not used[i]: 24 | chosen.append(i) 25 | used[i] = 1 26 | generate() 27 | chosen.pop() 28 | used[i] = 0 29 | 30 | generate() 31 | 32 | 33 | if __name__ == '__main__': 34 | N, R = (int(n) for n in input().split()) 35 | combinations(N, R) 36 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_15651_N_and_M_3.py: -------------------------------------------------------------------------------- 1 | """Print out permutations with duplications 2 | 3 | https://www.acmicpc.net/problem/15651 4 | """ 5 | import sys 6 | 7 | write = sys.stdout.write 8 | 9 | 10 | def permutations(n, r): 11 | chosen = [] 12 | 13 | def generate(): 14 | if len(chosen) == r: 15 | for i in range(len(chosen)): 16 | write(str(chosen[i]) + ' ') 17 | write('\n') 18 | return 19 | 20 | for i in range(1, n + 1): 21 | chosen.append(i) 22 | generate() 23 | chosen.pop() 24 | generate() 25 | 26 | 27 | if __name__ == '__main__': 28 | N, R = (int(n) for n in input().split()) 29 | permutations(N, R) 30 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_15652_N_and_M_4.py: -------------------------------------------------------------------------------- 1 | """Print out permutations with duplications in ascending order 2 | 3 | https://www.acmicpc.net/problem/15652 4 | """ 5 | import sys 6 | 7 | write = sys.stdout.write 8 | 9 | 10 | def permutations(n, r): 11 | chosen = [] 12 | 13 | def generate(): 14 | if len(chosen) == r: 15 | for i in range(len(chosen)): 16 | write(str(chosen[i]) + ' ') 17 | write('\n') 18 | return 19 | 20 | start = chosen[-1] if chosen else 1 21 | 22 | for i in range(start, n + 1): 23 | chosen.append(i) 24 | generate() 25 | chosen.pop() 26 | generate() 27 | 28 | 29 | if __name__ == '__main__': 30 | N, R = (int(n) for n in input().split()) 31 | permutations(N, R) 32 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1619_pick_out_points.py: -------------------------------------------------------------------------------- 1 | #### WARNING #### 2 | ### NOT SOLVED ## 3 | ### ######## #### 4 | 5 | 6 | """Get the maximum number of points located in a single 1D line 7 | 8 | url: https://www.acmicpc.net/problem/1619 9 | """ 10 | from collections import namedtuple, Counter 11 | import sys 12 | 13 | input = sys.stdin.readline 14 | Point = namedtuple('Point', ['x', 'y']) 15 | 16 | 17 | def max_points_crossing_line(points): 18 | P = len(points) 19 | INF = float('inf') 20 | line_counter = Counter() 21 | 22 | for i in range(P): 23 | p1 = points[i] 24 | for j in range(i+1, P): 25 | p2 = points[j] 26 | if p1.x - p2.x == 0: 27 | gradient = INF 28 | else: 29 | gradient = (p1.y - p2.y) / (p1.x - p2.x) 30 | intercept = p1.y - gradient * p1.x 31 | line_counter[(gradient, intercept)] += 1 32 | 33 | comb = line_counter.most_common(1)[0][1] 34 | 35 | n = 2 36 | while True: 37 | if n * (n - 1) // 2 == comb: 38 | break 39 | n += 1 40 | 41 | return n if n >= 3 else -1 42 | 43 | 44 | if __name__ == '__main__': 45 | N = int(input()) 46 | points = [] 47 | for _ in range(N): 48 | x, y = (int(n) for n in input().split()) 49 | p = Point(x, y) 50 | points.append(p) 51 | 52 | print(max_points_crossing_line(points)) 53 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1654_cutting_off_lan_wires.py: -------------------------------------------------------------------------------- 1 | """Get maximum length of cutted lan wires 2 | 3 | url: https://www.acmicpc.net/problem/1654 4 | """ 5 | import sys 6 | 7 | input = sys.stdin.readline 8 | 9 | 10 | def max_wire_length(arr, MIN_REQUIRED): 11 | def number_of_wires(length): 12 | return sum(n // length for n in arr) 13 | 14 | def search_max_len(lo, hi): 15 | if lo == hi: 16 | return hi 17 | 18 | mid = (lo + hi) // 2 + 1 # 이 코드가 핵심. 왜 1을 더할까요? 19 | if number_of_wires(mid) >= MIN_REQUIRED: 20 | return search_max_len(mid, hi) 21 | else: 22 | return search_max_len(lo, mid-1) 23 | 24 | return search_max_len(1, max(arr)) 25 | 26 | 27 | if __name__ == '__main__': 28 | K, MIN_REQUIRED = [int(n) for n in input().split()] 29 | arr = [] 30 | 31 | for _ in range(K): 32 | arr.append(int(input())) 33 | 34 | print(max_wire_length(arr, MIN_REQUIRED)) 35 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1655_tell_median.py: -------------------------------------------------------------------------------- 1 | """Tell running median of each input in array 2 | 3 | url: https://www.acmicpc.net/problem/1655 4 | """ 5 | from heapq import heappop, heappush 6 | import sys 7 | 8 | input = sys.stdin.readline 9 | 10 | 11 | if __name__ == '__main__': 12 | max_heap, min_heap = [], [] 13 | N = int(input()) 14 | 15 | # Loop invariant 16 | # max_heap as A, min_heap as B 17 | # 18 | # 1. MAX(A) <= MIN(B) 19 | # 2. |A| - |B| <= 1 20 | # 3. left median is MAX(A) 21 | for _ in range(N): 22 | n = int(input()) 23 | 24 | if len(max_heap) == len(min_heap): 25 | if min_heap and n > min_heap[0]: 26 | v = heappop(min_heap) 27 | heappush(max_heap, -v) 28 | heappush(min_heap, n) 29 | else: 30 | heappush(max_heap, -n) 31 | else: # size of max heap is 1 bigger than min heap 32 | if max_heap and -max_heap[0] > n: 33 | v = -heappop(max_heap) 34 | heappush(max_heap, -n) 35 | heappush(min_heap, v) 36 | else: 37 | heappush(min_heap, n) 38 | 39 | print(-max_heap[0]) 40 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_18258_queue_2.py: -------------------------------------------------------------------------------- 1 | """Implement queue and do some jobs 2 | 3 | https://www.acmicpc.net/problem/18258 4 | """ 5 | from collections import deque 6 | import sys 7 | 8 | input = sys.stdin.readline 9 | write = sys.stdout.write 10 | 11 | 12 | if __name__ == '__main__': 13 | queue = deque() 14 | N = int(input()) 15 | 16 | for _ in range(N): 17 | cmd, *v = input().strip().split() 18 | if cmd == 'push': 19 | v = v[0] 20 | queue.append(v) 21 | elif cmd == 'front': 22 | if not queue: 23 | write('-1\n') 24 | else: 25 | write(queue[0] + '\n') 26 | elif cmd == 'back': 27 | if not queue: 28 | write('-1\n') 29 | else: 30 | write(queue[-1] + '\n') 31 | elif cmd == 'size': 32 | write(str(len(queue)) + '\n') 33 | elif cmd == 'empty': 34 | if not queue: 35 | write('1\n') 36 | else: 37 | write('0\n') 38 | elif cmd == 'pop': 39 | if not queue: 40 | write('-1\n') 41 | else: 42 | write(queue.popleft() + '\n') 43 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1920_binary_search.py: -------------------------------------------------------------------------------- 1 | """Return whether element is in the array 2 | 3 | url: https://www.acmicpc.net/problem/1920 4 | """ 5 | def binary_search(arr, v, is_sorted=True): 6 | SIZE = len(arr) 7 | 8 | if not is_sorted: 9 | arr.sort() 10 | 11 | def move_on(lo, hi): 12 | if lo == hi: 13 | return (True, lo) if arr[lo] == v else (False, -1) 14 | 15 | mid = (lo + hi) // 2 16 | if arr[mid] >= v: 17 | return move_on(lo, mid) 18 | else: 19 | return move_on(mid+1, hi) 20 | 21 | return move_on(0, SIZE-1) 22 | 23 | 24 | if __name__ == '__main__': 25 | input() 26 | arr = [int(n) for n in input().split()] 27 | arr.sort() 28 | input() 29 | targets = [int(n) for n in input().split()] 30 | 31 | for t in targets: 32 | exists, _ = binary_search(arr, t) 33 | print(1 if exists else 0) 34 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1927_min_heap.py: -------------------------------------------------------------------------------- 1 | """Implement min heap 2 | 3 | url: https://www.acmicpc.net/problem/1927 4 | """ 5 | from heapq import * 6 | import sys 7 | 8 | input = sys.stdin.readline 9 | 10 | 11 | def do_calculations(cmds, min_heap=True): 12 | POPOUT = 0 13 | ret = [] 14 | heap = [] 15 | 16 | for cmd in cmds: 17 | if cmd == POPOUT: 18 | if not heap: 19 | ret.append(0) 20 | else: 21 | _, value = heappop(heap) 22 | ret.append(value) 23 | else: 24 | priority = cmd if min_heap else -cmd 25 | heappush(heap, (priority, cmd)) 26 | 27 | return ret 28 | 29 | 30 | if __name__ == '__main__': 31 | N = int(input()) 32 | cmds = [] 33 | 34 | for _ in range(N): 35 | cmds.append(int(input().strip())) 36 | 37 | for r in do_calculations(cmds, min_heap=True): 38 | print(r) 39 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_1966_printer_queue.py: -------------------------------------------------------------------------------- 1 | """Print order of specific number to be printed 2 | 3 | url: https://www.acmicpc.net/problem/1966 4 | """ 5 | from collections import deque 6 | 7 | 8 | def get_order(arr, nth): 9 | arr = deque((i == nth, n) for i, n in enumerate(arr)) 10 | importances = [0] * 10 11 | 12 | for i, n in arr: 13 | importances[n] += 1 14 | 15 | count = 1 16 | while arr: 17 | is_target, n = arr.popleft() 18 | 19 | if any(importances[big] > 0 for big in range(n+1, 10)): 20 | arr.append((is_target, n)) 21 | else: 22 | if is_target: 23 | return count 24 | else: 25 | importances[n] -= 1 26 | count += 1 27 | 28 | 29 | if __name__ == '__main__': 30 | T = int(input()) 31 | ans = [] 32 | 33 | for _ in range(T): 34 | _, nth = (int(n) for n in input().split()) 35 | arr = [int(n) for n in input().split()] 36 | ans.append(get_order(arr, nth)) 37 | 38 | for n in ans: 39 | print(n) 40 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_2110_installing_routers.py: -------------------------------------------------------------------------------- 1 | """Get maximum distances among routers along the straight line 2 | 3 | url: https://www.acmicpc.net/problem/2110 4 | """ 5 | import sys 6 | 7 | input = sys.stdin.readline 8 | 9 | 10 | def count_installed_routers(locs, DIST): 11 | cnt = 1 12 | cur_loc = 0 13 | 14 | for l in range(1, len(locs)): 15 | if locs[l] - locs[cur_loc] >= DIST: 16 | cnt += 1 17 | cur_loc = l 18 | return cnt 19 | 20 | 21 | def max_distances(locs, C, is_sorted=True): 22 | if not is_sorted: 23 | locs.sort() 24 | 25 | start = min(locs[i+1] - locs[i] for i in range(len(locs)-1)) 26 | end = locs[-1] - locs[0] 27 | 28 | while start <= end: 29 | mid = (start + end) // 2 30 | installed_count = count_installed_routers(locs, mid) 31 | 32 | if installed_count < C: 33 | end = mid - 1 34 | elif installed_count >= C: 35 | ans = mid 36 | start = mid + 1 37 | 38 | return ans 39 | 40 | 41 | if __name__ == '__main__': 42 | N, C = (int(n) for n in input().split()) 43 | locs = [] 44 | 45 | for _ in range(N): 46 | locs.append(int(input())) 47 | 48 | locs.sort() 49 | print(max_distances(locs, C)) 50 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_2164_card2.py: -------------------------------------------------------------------------------- 1 | """Get last number in the deck 2 | 3 | url: https://www.acmicpc.net/problem/2164 4 | """ 5 | from collections import deque 6 | from math import log2 7 | 8 | 9 | # Brute force 10 | def last_man_standing(N): 11 | deck = deque(range(1, N+1)) 12 | is_throw_turn = True 13 | 14 | while len(deck) > 1: 15 | first = deck.popleft() 16 | if not is_throw_turn: 17 | deck.append(first) 18 | 19 | is_throw_turn ^= True 20 | 21 | return deck[0] 22 | 23 | 24 | # O(1) Way 25 | def last_man_standing(N): 26 | e = int(log2(N)) 27 | n = 2 ** e 28 | return N if (N & (N - 1)) == 0 else (N - n) * 2 29 | 30 | 31 | if __name__ == '__main__': 32 | n = int(input()) 33 | print(last_man_standing(n)) 34 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_2805_chopping_woods.py: -------------------------------------------------------------------------------- 1 | """Get tallest height to chop off woods to get required lumber 2 | 3 | url: https://www.acmicpc.net/problem/2805 4 | """ 5 | def get_tallest_heights(MIN_REQUIRED, heights): 6 | def lumber_got(height): 7 | ret = 0 8 | for h in heights: 9 | ret += max(0, h - height) 10 | 11 | return ret 12 | 13 | def get_height(lo, hi): 14 | if lo == hi: 15 | return lo 16 | 17 | mid = (lo + hi) // 2 + 1 18 | if lumber_got(mid) >= MIN_REQUIRED: 19 | return get_height(mid, hi) 20 | else: 21 | return get_height(lo, mid-1) 22 | 23 | return get_height(0, max(heights)) 24 | 25 | 26 | if __name__ == '__main__': 27 | _, MIN_REQUIRED = (int(n) for n in input().split()) 28 | heights = [int(n) for n in input().split()] 29 | print(get_tallest_heights(MIN_REQUIRED, heights)) 30 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/no_5430_AC.py: -------------------------------------------------------------------------------- 1 | """Do AC language calculations over integer array 2 | 3 | url: https://www.acmicpc.net/problem/5430 4 | """ 5 | from collections import deque 6 | 7 | ERROR_MESSAGE = 'error' 8 | REVERSE, DISCARD = 'RD' 9 | 10 | 11 | def do_ac_calculations(arr, cmds): 12 | deck = deque(arr) 13 | 14 | # Preprocess commands 15 | tmp_r = 0 16 | new_cmds = '' 17 | 18 | for c in cmds: 19 | if c == DISCARD: 20 | new_cmds += REVERSE if tmp_r % 2 else '' 21 | new_cmds += DISCARD 22 | tmp_r = 0 23 | else: 24 | tmp_r += 1 25 | 26 | new_cmds += REVERSE if tmp_r % 2 else '' 27 | 28 | 29 | # Do real calculations 30 | reverse_now = False 31 | for c in new_cmds: 32 | if c == REVERSE: 33 | reverse_now ^= True 34 | else: 35 | if not deck: 36 | return ERROR_MESSAGE 37 | 38 | if reverse_now: 39 | deck.pop() 40 | else: 41 | deck.popleft() 42 | 43 | if reverse_now: 44 | deck.reverse() 45 | 46 | return list(deck) 47 | 48 | 49 | if __name__ == '__main__': 50 | T = int(input()) 51 | ans = [] 52 | 53 | for _ in range(T): 54 | cmds = input() 55 | input() 56 | arr = eval(input()) 57 | ans.append(do_ac_calculations(arr, cmds)) 58 | 59 | for ret in ans: 60 | ret = str(ret).replace(' ', '') 61 | print(ret) 62 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/oreun_numbers.py: -------------------------------------------------------------------------------- 1 | """Get the right most large numbers from array 2 | 3 | url: https://www.acmicpc.net/problem/17298 4 | """ 5 | def get_oreun_numbers(nums): 6 | stack = [] 7 | ans = [-1] * len(nums) 8 | 9 | for i, n in enumerate(nums): 10 | while stack: 11 | prev_i, prev_n = stack[-1] 12 | if prev_n < n: 13 | stack.pop() 14 | ans[prev_i] = n 15 | else: 16 | break 17 | 18 | stack.append((i, n)) 19 | 20 | return ans 21 | 22 | 23 | if __name__ == '__main__': 24 | _ = int(input()) 25 | arr = [int(n) for n in input().split()] 26 | print(' '.join(str(n) for n in get_oreun_numbers(arr))) 27 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/ox_quiz.py: -------------------------------------------------------------------------------- 1 | """Get total score in a given OX string 2 | 3 | :input: 4 | 5 5 | OOXXOXXOOO 6 | OOXXOOXXOO 7 | OXOXOXOXOXOXOX 8 | OOOOOOOOOO 9 | OOOOXOOOOXOOOOX 10 | 11 | :output: 12 | 10 13 | 9 14 | 7 15 | 55 16 | 30 17 | 18 | ID : OX quiz 19 | url : https://www.acmicpc.net/problem/8958 20 | """ 21 | def sum_from(n, _from=0): 22 | return _from if n == _from else n + sum_from(n-1, _from) 23 | 24 | 25 | def get_total_score(ox): 26 | ox = 'X' + ox + 'X' 27 | last = 0 28 | score = 0 29 | for i in range(1, len(ox)): 30 | if ox[i] == 'X': 31 | count = i - last - 1 32 | score += sum_from(count) 33 | last = i 34 | return score 35 | 36 | 37 | if __name__ == '__main__': 38 | N = int(input()) 39 | oxs = [] 40 | for _ in range(N): 41 | oxs.append(get_total_score(input())) 42 | 43 | for n in oxs: 44 | print(n) 45 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/padovan_sequence.py: -------------------------------------------------------------------------------- 1 | """Return the nth Padovan Sequence 2 | 3 | :input: 4 | 2 5 | 6 6 | 12 7 | 8 | :return: 9 | 3 10 | 16 11 | 12 | url: https://www.acmicpc.net/problem/9461 13 | """ 14 | arr = [] 15 | ans = [] 16 | max_v = -1 17 | C = int(input()) 18 | 19 | for _ in range(C): 20 | n = int(input()) 21 | arr.append(n) 22 | max_v = max(max_v, n) 23 | 24 | cache = [-1 for _ in range(max_v+1)] 25 | 26 | 27 | def padovan(n): 28 | if n < 4: 29 | return 1 30 | elif cache[n] != -1: 31 | return cache[n] 32 | else: 33 | cache[n] = padovan(n-2) + padovan(n-3) 34 | return cache[n] 35 | 36 | 37 | for n in arr: 38 | ans.append(padovan(n)) 39 | 40 | for n in ans: 41 | print(n) 42 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/police_car.py: -------------------------------------------------------------------------------- 1 | """Return shortest sum of distances cars moved and print each move 2 | 3 | :input: 4 | 6 5 | 3 6 | 3 5 7 | 5 5 8 | 2 3 9 | 10 | :return: 11 | 9 12 | 2 13 | 2 14 | 1 15 | 16 | url: https://www.acmicpc.net/problem/2618 17 | """ 18 | import sys 19 | sys.setrecursionlimit(10 ** 12) 20 | 21 | 22 | def func(N, cases): 23 | cases = [(1, 1), (N, N)] + cases 24 | cache = [[-1 for _ in range(N+1)] for _ in range(N+1)] 25 | routes = [] 26 | 27 | def dist(x, y): 28 | pos1, pos2 = cases[x], cases[y] 29 | return abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1]) 30 | 31 | def calc(x, y): 32 | if max(x, y) >= len(cases) - 1: 33 | return 0 34 | elif cache[x][y] != -1: 35 | return cache[x][y] 36 | 37 | nxt = max(x, y) + 1 38 | cache[x][y] = min(calc(nxt, y) + dist(nxt, x), 39 | calc(x, nxt) + dist(y, nxt)) 40 | return cache[x][y] 41 | 42 | def generate_route(x, y, nth): 43 | if nth == len(cases): 44 | return 45 | 46 | if calc(nth, y) + dist(nth, x) < calc(x, nth) + dist(y, nth): 47 | routes.append(1) 48 | generate_route(nth, y, nth+1) 49 | else: 50 | routes.append(2) 51 | generate_route(x, nth, nth+1) 52 | 53 | 54 | generate_route(0, 1, 2) 55 | return calc(0, 1), routes 56 | 57 | 58 | if __name__ == '__main__': 59 | N = int(input()) 60 | C = int(input()) 61 | cases = [] 62 | for _ in range(C): 63 | x, y = (int(n) for n in input().split()) 64 | cases.append((x, y)) 65 | 66 | min_dist, routes = func(N, cases) 67 | print(min_dist) 68 | 69 | for i in range(len(routes)): 70 | if i != len(routes) - 1: 71 | print(routes[i]) 72 | else: 73 | print(routes[i], end='') 74 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/queue.py: -------------------------------------------------------------------------------- 1 | """Implement queue and do some chores 2 | 3 | :input: 4 | 15 5 | push 1 6 | push 2 7 | front 8 | back 9 | size 10 | empty 11 | pop 12 | pop 13 | pop 14 | size 15 | empty 16 | pop 17 | push 3 18 | empty 19 | front 20 | 21 | :return: 22 | 1 23 | 2 24 | 2 25 | 0 26 | 1 27 | 2 28 | -1 29 | 0 30 | 1 31 | -1 32 | 0 33 | 3 34 | 35 | url: https://www.acmicpc.net/problem/10845 36 | """ 37 | class Queue: 38 | def __init__(self): 39 | self._queue = [] 40 | self._len = 0 41 | 42 | def push(self, v): 43 | self._queue.append(v) 44 | self._len += 1 45 | 46 | def pop(self): 47 | if self.empty(): 48 | return -1 49 | self._len -= 1 50 | return self._queue.pop(0) 51 | 52 | def size(self): 53 | return self._len 54 | 55 | def empty(self): 56 | return 1 if self._len == 0 else 0 57 | 58 | def front(self): 59 | if self.empty(): 60 | return -1 61 | return self._queue[0] 62 | 63 | def back(self): 64 | if self.empty(): 65 | return -1 66 | return self._queue[-1] 67 | 68 | 69 | if __name__ == '__main__': 70 | C = int(input()) 71 | ans = [] 72 | queue = Queue() 73 | for _ in range(C): 74 | line = input() 75 | if line == 'front': 76 | ans.append(queue.front()) 77 | elif line == 'back': 78 | ans.append(queue.back()) 79 | elif line == 'size': 80 | ans.append(queue.size()) 81 | elif line == 'empty': 82 | ans.append(queue.empty()) 83 | elif line == 'pop': 84 | ans.append(queue.pop()) 85 | else: 86 | _, num = line.split() 87 | num = int(num) 88 | queue.push(num) 89 | 90 | for n in ans: 91 | print(n) 92 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/remote_controller.py: -------------------------------------------------------------------------------- 1 | """Get minimal number of turning to wanted channels 2 | 3 | :input: 4 | 5457 5 | 3 6 | 6 7 8 7 | 8 | :return: 9 | 6 10 | """ 11 | def min_clicks(N, channels, BASE=100): 12 | ret = abs(N - BASE) 13 | channels_cands = [] 14 | N = str(N) 15 | l = len(N) 16 | 17 | def generate(i, tmp_str): 18 | nonlocal channels_cands 19 | if i == l: 20 | diff = abs(int(N) - int(tmp_str)) 21 | channels_cands.append((diff + len(tmp_str), tmp_str)) 22 | return 23 | 24 | t = N[i] 25 | if channels[int(t)]: 26 | generate(i+1, tmp_str+t) 27 | return 28 | 29 | d = 1 30 | going_on = True 31 | while going_on and d < 10: 32 | if int(t) + d < 10 and channels[int(t)+d]: 33 | generate(i+1, tmp_str+str(int(t)+d)) 34 | going_on = False 35 | if int(t) - d >= 0 and channels[int(t)-d]: 36 | generate(i+1, tmp_str+str(int(t)-d)) 37 | going_on = False 38 | d += 1 39 | 40 | channels_cands.sort() 41 | generate(0, '') 42 | return min(ret, channels_cands[0][0]) 43 | 44 | 45 | if __name__ == '__main__': 46 | N = int(input()) 47 | M = int(input()) 48 | channels = [1 for _ in range(10)] 49 | for n in input().split(): 50 | channels[int(n)] = 0 51 | 52 | print(min_clicks(N, channels)) 53 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/rgb.py: -------------------------------------------------------------------------------- 1 | """Return minimum cost of painting the roofs of houses in a row 2 | 3 | :input: 4 | 3 5 | 26 40 83 6 | 49 60 57 7 | 13 89 99 8 | 9 | :return: 10 | 96 11 | """ 12 | import sys 13 | sys.setrecursionlimit(10 ** 6) 14 | 15 | INF = 987654321 16 | 17 | def min_cost(arr): 18 | length = len(arr) 19 | cache = [[-1 for _ in range(3)] for _ in range(length)] 20 | colors = 'RGB' 21 | ans = ['' for _ in range(length)] 22 | 23 | def cal_cost(loc, color): 24 | if loc < 0: 25 | return 0 26 | elif cache[loc][color] != -1: 27 | return cache[loc][color] 28 | 29 | tmp = INF 30 | for c in range(3): 31 | if c != color: 32 | tmp = min(tmp, cal_cost(loc-1, c) + arr[loc][color]) 33 | cache[loc][color] = tmp 34 | return tmp 35 | 36 | def nth_min_cost(loc): 37 | return min(cal_cost(loc, i) for i in range(3)) 38 | 39 | def generate(loc, last): 40 | if loc < 0: 41 | return '' 42 | if cal_cost(loc, (last+1) % 3) < cal_cost(loc, (last+2) % 3): 43 | last = (last + 1) % 3 44 | else: 45 | last = (last + 2) % 3 46 | ans[loc] = colors[last] 47 | generate(loc-1, last) 48 | 49 | #### If you want to get minimum cost 50 | return nth_min_cost(length-1) 51 | 52 | #### If you want to get a list of colors that makes up minimum costs 53 | min_value = nth_min_cost(length-1) + 1 54 | for i in range(3): 55 | if cal_cost(length-1, i) < min_value: 56 | min_value = cal_cost(length-1, i) 57 | last = i 58 | ans[length-1] = colors[last] 59 | generate(length-2, last) 60 | return ''.join(ans) 61 | 62 | 63 | if __name__ == '__main__': 64 | N = int(input()) 65 | arr = [] 66 | for _ in range(N): 67 | arr.append([int(n) for n in input().split()]) 68 | print(min_cost(arr)) 69 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/trailing_zeros_binomial_coefficient.py: -------------------------------------------------------------------------------- 1 | """Return number of trailing zeros of given binomial coefficient 2 | 3 | :input: 4 | 25 12 5 | 6 | :return: 7 | 2 8 | 9 | For information of trailing zeros of factorial N(N!), 10 | visit my place and behold how it shall be: 11 | https://shoark7.github.io/programming/algorithm/number-of-trailing-zeros-in-factorial 12 | 13 | 14 | URL: https://www.acmicpc.net/problem/2004 15 | ID : 2004 16 | """ 17 | def g(n, f): 18 | counts = 0 19 | tmp_f = f 20 | while n >= tmp_f: 21 | counts += (n // tmp_f) 22 | tmp_f *= f 23 | return counts 24 | 25 | def trailing_zeros_combi(n, m): 26 | return min(g(n, 5) - g(m, 5) - g(n - m, 5), 27 | g(n, 2) - g(m, 2) - g(n - m, 2)) 28 | 29 | 30 | if __name__ == '__main__': 31 | n, m = (int(x) for x in input().split()) 32 | print(trailing_zeros_combi(n, m)) 33 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/tree_traverse.py: -------------------------------------------------------------------------------- 1 | """Print the sequence of pre, in, postorder traversal of a binary tree 2 | 3 | :input: 4 | 7 5 | A B C 6 | B D . 7 | C E F 8 | E . . 9 | F . G 10 | D . . 11 | G . . 12 | 13 | :return: 14 | ABDCEFG 15 | DBAECFG 16 | DBEGFCA 17 | 18 | url: https://www.acmicpc.net/problem/1991 19 | """ 20 | import string 21 | 22 | 23 | def traverse(root, nodes, direction): 24 | ans = '' 25 | def find(root): 26 | nonlocal ans 27 | if root is None: 28 | return 29 | 30 | cha, left, right = nodes[root] 31 | if direction == 'pre': 32 | ans += cha 33 | find(left) 34 | find(right) 35 | elif direction == 'in': 36 | find(left) 37 | ans += cha 38 | find(right) 39 | else: 40 | find(left) 41 | find(right) 42 | ans += cha 43 | find(root) 44 | return ans 45 | 46 | 47 | if __name__ == '__main__': 48 | CAPS = string.ascii_uppercase 49 | N = int(input()) 50 | nodes = [None for _ in range(N)] 51 | 52 | for _ in range(N): 53 | parent, left, right = input().split() 54 | left = CAPS.index(left) if left != '.' else None 55 | right = CAPS.index(right) if right != '.' else None 56 | nodes[CAPS.index(parent)] = [parent, left, right] 57 | 58 | print(traverse(0, nodes, 'pre')) 59 | print(traverse(0, nodes, 'in')) 60 | print(traverse(0, nodes, 'post')) 61 | -------------------------------------------------------------------------------- /problems_solving/baekjoon/wire.py: -------------------------------------------------------------------------------- 1 | """Get number of mininum number of single wires not for them to be twisted 2 | :input: 3 | 8 4 | 1 8 5 | 3 9 6 | 2 2 7 | 4 1 8 | 6 4 9 | 10 10 10 | 9 7 11 | 7 6 12 | 13 | :return: 14 | 3 15 | 16 | url: https://www.acmicpc.net/problem/2565 17 | No : 2565 18 | """ 19 | def min_wire_to_remove(points): 20 | points.sort(key=lambda x: x[0]) 21 | points = [x[1] for x in points] 22 | cache = [0] * len(points) 23 | cache[0] = 1 24 | 25 | for i in range(1, len(points)): 26 | tmp_ans = 0 27 | for j in range(i): 28 | if points[j] < points[i]: 29 | tmp_ans = max(tmp_ans, cache[j]) 30 | cache[i] = tmp_ans + 1 31 | return len(points) - max(cache) 32 | 33 | 34 | if __name__ == '__main__': 35 | C = int(input()) 36 | points = [] 37 | for _ in range(C): 38 | c = tuple(int(n) for n in input().split()) 39 | points.append(c) 40 | print(min_wire_to_remove(points)) 41 | -------------------------------------------------------------------------------- /problems_solving/kakao/2020-blind-algorithm-test/q1_string_compression.py: -------------------------------------------------------------------------------- 1 | """2020 카카오 신입 개발자 블라인드 테스트 1: 문자열 압축 2 | 3 | * 핵심 아이디어: 4 | 1. 자르는 길이는 1부터 (|S| // 2) 까지 5 | 2. 숫자를 더할 때 1은 더하지 않는다는 사실을 기억하자. 6 | 3. 자르는 stride가 특정수일 때의 함수를 만들어 이를 반복문으로 실행해 최소값을 찾자. 7 | 8 | 9 | 문제 URL: https://programmers.co.kr/learn/courses/30/lessons/60057 10 | """ 11 | def solution(s): 12 | def length_of(s, length): 13 | substring_count = len(s) // length 14 | does_rest_exist = (len(s) % length != 0) 15 | ans = -length 16 | 17 | count = 1 18 | tmp_str = '' 19 | for idx in range(substring_count): 20 | str_now = s[idx*length:idx*length+length] 21 | 22 | if str_now == tmp_str: 23 | count += 1 24 | else: 25 | ans += length 26 | ans += int(len(str(count))) if count != 1 else 0 27 | count = 1 28 | tmp_str = str_now 29 | 30 | if idx == substring_count - 1: 31 | ans += length 32 | ans += int(len(str(count))) if count != 1 else 0 33 | 34 | if does_rest_exist: 35 | ans += len(s) - substring_count * length 36 | 37 | return ans 38 | 39 | return min(length_of(s, l) for l in range(1, len(s) // 2+2)) 40 | -------------------------------------------------------------------------------- /problems_solving/kakao/2020-blind-algorithm-test/q2_parenthesis_transformation.py: -------------------------------------------------------------------------------- 1 | """2020 카카오 신입 개발자 블라인드 테스트 2: 괄호 변환 2 | 3 | * 핵심 아이디어: 4 | 1. 재귀함수를 짜는 게 핵심이다. 천천히, 정의되어 있는 대로 함수를 만들어나간다. 5 | 2. 파이썬의 기본 재귀 한계는 1000이다. 입력 괄호의 길이의 상한 또한 1000이므로, 6 | 별다른 수정이 필요없다. 7 | 8 | 9 | 문제 URL: https://programmers.co.kr/learn/courses/30/lessons/60058 10 | """ 11 | def solution(p): 12 | OPENER, CLOSER = '()' 13 | 14 | def is_balanced(p): 15 | return p.count(OPENER) == p.count(CLOSER) 16 | 17 | def is_correct(parens): 18 | count = 0 19 | for p in parens: 20 | count += 1 if p == OPENER else -1 21 | if count < 0: 22 | return False 23 | return count == 0 24 | 25 | def process_parens(p): 26 | if not p: 27 | return p 28 | 29 | for i in range(2, len(p)+1, 2): 30 | if is_balanced(p[:i]): 31 | A, B = p[:i], p[i:] 32 | break 33 | 34 | if is_correct(A): 35 | return A + process_parens(B) 36 | else: 37 | B = OPENER + process_parens(B) + CLOSER 38 | A = A[1:-1] 39 | A = ''.join(CLOSER if a == OPENER else OPENER for a in A) 40 | return B + A 41 | 42 | return process_parens(p) 43 | -------------------------------------------------------------------------------- /problems_solving/kakao/2020-blind-algorithm-test/q3_lock_and_key.py: -------------------------------------------------------------------------------- 1 | """2020 카카오 신입 개발자 블라인드 테스트 3: 자물쇠와 열쇠 2 | 3 | * 핵심 아이디어: 4 | 1. 무조건 자물쇠의 크기가 키의 크기의 이상이다. 5 | 자물쇠의 크기를 3배로 키우고, 자물쇠를 그 가운데에 두어 범위를 벗어나는 것을 피할 수 있다. 6 | 2. 키를 90도로 최대 4번 돌린다. 따라서 해당 알고리즘을 미리 준비해두면 좋다. 7 | 8 | 9 | 문제 URL: https://programmers.co.kr/learn/courses/30/lessons/60059 10 | """ 11 | def rotate_matrix_90(matrix): 12 | N = len(matrix) 13 | ret = [[0] * N for _ in range(N)] 14 | 15 | for r in range(N): 16 | for c in range(N): 17 | ret[c][N-r-1] = matrix[r][c] 18 | 19 | return ret 20 | 21 | 22 | def solution(key, lock): 23 | K, L = len(key), len(lock) 24 | padded_lock = [[None] * L * 3 for _ in range(L * 3)] 25 | holes_count = 0 26 | 27 | for r in range(L): 28 | for c in range(L): 29 | padded_lock[L+r][L+c] = lock[r][c] 30 | if lock[r][c] == 0: 31 | holes_count += 1 32 | 33 | def does_match_here_well(sr, sc): 34 | matched_count = 0 35 | for kr in range(K): 36 | for kc in range(K): 37 | if key[kr][kc] == 1 and padded_lock[sr+kr][sc+kc] == 1: 38 | return False 39 | elif key[kr][kc] == 1 and padded_lock[sr+kr][sc+kc] == 0: 40 | matched_count += 1 41 | 42 | return matched_count == holes_count 43 | 44 | 45 | for _ in range(360 // 90): 46 | key = rotate_matrix_90(key) 47 | 48 | for sr in range(3 * L - K): 49 | for sc in range(3 * L - K): # 's' means 'start' here 50 | if does_match_here_well(sr, sc): 51 | return True 52 | 53 | return False 54 | -------------------------------------------------------------------------------- /problems_solving/kakao/2020-blind-algorithm-test/q6_check_outerwall.py: -------------------------------------------------------------------------------- 1 | """2020 카카오 신입 개발자 블라인드 테스트 6: 외벽 점검 2 | 3 | * 핵심 아이디어: 4 | 1. 순환하는 외벽 구조는 각 점을 맨 뒤로 이어붙이면서 해결한다. 5 | 2. 필요한 친구 수는 1명부터 D명까지 늘려가되, 각 인원들의 순열도 고려해서 확인한다. 6 | 7 | 8 | 문제 URL: https://programmers.co.kr/learn/courses/30/lessons/60062 9 | """ 10 | from itertools import permutations 11 | 12 | 13 | def solution(N, weak, dist): 14 | # process data 15 | dist.sort(reverse=True) 16 | weak_list = [weak] 17 | 18 | for _ in range(len(weak)-1): 19 | last = weak_list[-1].copy() 20 | first = last.pop(0) 21 | last.append(N + first) 22 | weak_list.append(last) 23 | 24 | # Solve the problem 25 | for manpower in range(1, len(dist)+1): 26 | for tmp_dist in permutations(dist[:manpower], manpower): 27 | for tmp_weak in weak_list: 28 | man_idx = 0 29 | weak_now = weak_idx = 0 30 | 31 | while man_idx < manpower and weak_idx < len(tmp_weak): 32 | if tmp_dist[man_idx] >= tmp_weak[weak_idx] - tmp_weak[weak_now]: 33 | weak_idx += 1 34 | else: 35 | weak_now = weak_idx 36 | man_idx += 1 37 | 38 | if weak_idx == len(tmp_weak) and man_idx < manpower: 39 | return manpower 40 | return -1 41 | -------------------------------------------------------------------------------- /problems_solving/kakao/code_festival_2018/data: -------------------------------------------------------------------------------- 1 | 6 2 | 8 4 3 | 13 19 4 | 8 10 5 | 18 18 6 | 8 25 7 | 13 16 8 | -------------------------------------------------------------------------------- /problems_solving/kakao/code_festival_2018/preliminary_1_bounty_hunter.py: -------------------------------------------------------------------------------- 1 | """Get sum of expected bounties 2 | 3 | :input: 4 | 6 5 | 8 4 6 | 13 19 7 | 8 10 8 | 18 18 9 | 8 25 10 | 13 16 11 | 12 | :return: 13 | 1780000 14 | 620000 15 | 1140000 16 | 420000 17 | 820000 18 | 620000 19 | 20 | url: https://www.acmicpc.net/problem/15953 21 | """ 22 | first_price = [5000000, 3000000, 2000000, 500000, 300000, 100000, 0] 23 | first_winner = [1, 2, 3, 4, 5, 6, 79] 24 | n_first = len(first_winner) 25 | p_first_winner = [0 for _ in range(n_first)] 26 | 27 | p_first_winner[0] = first_winner[0] 28 | for i in range(1, len(first_winner)): 29 | p_first_winner[i] = p_first_winner[i-1] + first_winner[i] 30 | 31 | 32 | second_price = [5120000, 2560000, 1280000, 640000, 320000, 0] 33 | second_winner = [1, 2, 4, 8, 16, 33] 34 | n_second = len(second_winner) 35 | p_second_winner = [0 for _ in range(n_second)] 36 | 37 | p_second_winner[0] = second_winner[0] 38 | for i in range(1, len(second_winner)): 39 | p_second_winner[i] = p_second_winner[i-1] + second_winner[i] 40 | 41 | 42 | def first_bounty(nth): 43 | if nth == 0: 44 | return 0 45 | for i in range(n_first): 46 | if nth <= p_first_winner[i]: 47 | return first_price[i] 48 | 49 | def second_bounty(nth): 50 | if nth == 0: 51 | return 0 52 | for i in range(n_second): 53 | if nth <= p_second_winner[i]: 54 | return second_price[i] 55 | 56 | 57 | if __name__ == '__main__': 58 | T = int(input()) 59 | ans = [] 60 | 61 | for _ in range(T): 62 | a, b = (int(n) for n in input().split()) 63 | ans.append(first_bounty(a) + second_bounty(b)) 64 | 65 | for n in ans: 66 | print(n) 67 | -------------------------------------------------------------------------------- /problems_solving/kakao/kakao_1_1.py: -------------------------------------------------------------------------------- 1 | """Kakaotal 1차 코딩 테스트 1번 문제 2 | 3 | http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/ 4 | """ 5 | import re 6 | 7 | 8 | if __name__ == '__main__': 9 | 4 = 5 10 | arr1 = [9, 20, 28, 18, 11] 11 | arr2 = [30, 1, 21, 17, 28] 12 | 13 | arr_mix = [a | b for a, b in zip(arr1, arr2)] 14 | arr_map = [] 15 | 16 | for arr in arr_mix: 17 | one_map = '' 18 | while arr > 1: 19 | arr, rest = divmod(arr, 2) 20 | one_map = ('#'+one_map) if rest else (' '+one_map) 21 | one_map = '#' + one_map 22 | one_map = re.sub('\s+', ' ', one_map) 23 | arr_map.append(one_map) 24 | 25 | 26 | 27 | print(arr_map) 28 | -------------------------------------------------------------------------------- /problems_solving/kakao/kakao_1_2.py: -------------------------------------------------------------------------------- 1 | """Kakaotal 1차 코딩 테스트 2번 문제 2 | 3 | http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/ 4 | """ 5 | SQUARES = 'SDT' 6 | OPTIONS = '*#' 7 | text = '1S*2T*3S' 8 | n_i = 0 9 | numbers = [] 10 | n_now = None 11 | 12 | 13 | for i in range(len(text)): 14 | n_c = text[i] 15 | if n_c.isnumeric(): 16 | if n_now: 17 | numbers.append(n_now) 18 | n_i += 1 19 | if text[i:i+2].isnumeric(): 20 | n_now = int(text[i:i+2]) 21 | i += 1 22 | else: 23 | n_now = int(n_c) 24 | elif n_c in SQUARES: 25 | if n_c == 'D': 26 | n_now **= 2 27 | elif n_c == 'T': 28 | n_now **= 3 29 | else: 30 | if n_c == '*': 31 | n_now *= 2 32 | if n_i != 0: 33 | numbers[n_i-1] *= 2 34 | else: 35 | n_now = -n_now 36 | numbers.append(n_now) 37 | 38 | 39 | print(sum(numbers)) 40 | -------------------------------------------------------------------------------- /problems_solving/kakao/kakao_1_3.py: -------------------------------------------------------------------------------- 1 | """Kakaotal 1차 코딩 테스트 3번 문제 2 | 3 | http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/ 4 | """ 5 | import time 6 | 7 | 8 | cities1 = ['Jeju', 'Pangyo', 'Seoul', 'NewYork', 'LA', 'Jeju', 'Pangyo', 'Seoul', 'NewYork', 'LA'] 9 | cities2 = ['Jeju', 'Pangyo', 'Seoul', 'NewYork', 'LA', 'SanFrancisco', 'Seoul', 'Rome', 'Paris', 'Jeju', 'NewYork', 'Rome'] 10 | cities3 = ['Jeju', 'Pangyo', 'Seoul', 'NewYork', 'LA', 'SanFrancisco', 'Seoul', 'Rome', 'Paris', 'Jeju', 'NewYork', 'Rome'] 11 | 12 | if __name__ == '__main__': 13 | LENGTH = 5 14 | HIT_TIME = 1 15 | MISS_TIME = 5 16 | cache = [' ' for _ in range(LENGTH)] 17 | tracer = [0 for _ in range(LENGTH)] 18 | hitted_index = '' 19 | total_time = 0 20 | oldest = 0 21 | next_value = 1 22 | 23 | 24 | if not LENGTH: 25 | print(len(cities3) * MISS_TIME) 26 | else: 27 | for city in cities3: 28 | is_hitted = False 29 | for i in range(LENGTH): 30 | if not is_hitted and city == cache[i] : 31 | is_hitted = True 32 | hitted_index = i 33 | oldest = i if tracer[i] < tracer[oldest] else oldest 34 | if is_hitted: 35 | tracer[hitted_index] += next_value 36 | next_value += 1 37 | total_time += 1 38 | else: 39 | tracer[oldest] = next_value 40 | next_value += 1 41 | cache[oldest] = city 42 | total_time += 5 43 | print(total_time) 44 | -------------------------------------------------------------------------------- /problems_solving/kakao/kakao_1_4.py: -------------------------------------------------------------------------------- 1 | START = 540 2 | 3 | 4 | if __name__ == '__main__': 5 | n = 2 6 | t = 10 7 | m = 2 8 | LAST = START + (n-1) * t 9 | timetable = ["09:10", "09:09", "08:00"] 10 | # timetable = ["08:00", "08:01", "08:22", "08:03"] 11 | # timetable = ['23:59'] * 10 12 | # timetable = ['00:01'] * 5 13 | timetable = [int(t[:2])*60 + int(t[3:]) for t in timetable] 14 | timetable.sort() 15 | timetable = [t for t in timetable if t <= LAST] 16 | 17 | rest = timetable 18 | s = START 19 | for i in range(n-1): 20 | s = START + i * t 21 | c = 0 22 | for r in rest[:m]: 23 | if r <= s: 24 | c += 1 25 | _, rest = rest[:c], rest[c:] 26 | s = LAST 27 | 28 | if len(rest) < m: 29 | answer = s 30 | else: 31 | answer = rest[-1] - 1 32 | 33 | hour, minute = divmod(answer, 60) 34 | print(f'{hour:02d}:{minute:02d}') 35 | -------------------------------------------------------------------------------- /problems_solving/programmers/number_to_124.py: -------------------------------------------------------------------------------- 1 | """Change an integer into format of 124 digit notation 2 | 3 | :input: 4 | 21 5 | 6 | :return: 7 | 124 8 | 9 | 10 | url : https://programmers.co.kr/learn/courses/30/lessons/12899 11 | date: 2019/05/24 12 | """ 13 | 14 | def solution(n): 15 | DIGIT_SET = '124' 16 | d = 1 17 | left = n - 1 # 왜 1을 빼는지가 핵심... 어렵다. 18 | ret = '' 19 | 20 | while 3 ** d <= left: 21 | left -= 3 ** d 22 | d += 1 23 | 24 | while d - 1 >= 0: 25 | index, left = divmod(left, 3 ** (d-1)) 26 | ret += DIGIT_SET[index] 27 | d -= 1 28 | 29 | return ret 30 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro004_largest_palindrome.py: -------------------------------------------------------------------------------- 1 | """앞에서부터 읽을 때나 뒤에서부터 읽을 때나 모양이 같은 수를 대칭수(palindrome)라고 부릅니다. 2 | 3 | 두 자리 수를 곱해 만들 수 있는 대칭수 중 가장 큰 수는 9009 (= 91 × 99) 입니다. 4 | 5 | 세 자리 수를 곱해 만들 수 있는 가장 큰 대칭수는 얼마입니까? 6 | 7 | 8 | Date: 2018/03/21 9 | """ 10 | 11 | 12 | def is_palindrome(n): 13 | n = str(n) 14 | length = len(n) 15 | isit = False 16 | mid = length // 2 17 | 18 | for i in range(mid): 19 | if n[i] != n[length-1-i]: 20 | return False 21 | 22 | return True 23 | 24 | max_value = 0 25 | 26 | 27 | for diff in range(900): 28 | a, b = 100, 100 + diff 29 | while b <= 999: 30 | if is_palindrome(a * b): 31 | max_value = max_value if max_value > a * b else a * b 32 | a += 1 33 | b += 1 34 | 35 | print(max_value) 36 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro005_lcm.py: -------------------------------------------------------------------------------- 1 | """ 2 | 1 ~ 10 사이의 어떤 수로도 나누어 떨어지는 가장 작은 수는 2520입니다. 3 | 4 | 그러면 1 ~ 20 사이의 어떤 수로도 나누어 떨어지는 가장 작은 수는 얼마입니까? 5 | """ 6 | from functools import reduce 7 | 8 | 9 | def is_prime(n): 10 | if n == 1: 11 | return False 12 | elif n in [2, 3]: 13 | return True 14 | 15 | for d in range(2, int(pow(n, 1/2))+1): 16 | if n % d == 0: 17 | return False 18 | return True 19 | 20 | 21 | def prime_number_generator(): 22 | n = 2 23 | while True: 24 | if is_prime(n): 25 | yield n 26 | n += 1 27 | 28 | 29 | def get_lcm(arr): 30 | generator = prime_number_generator() 31 | ns = [] 32 | 33 | while True: 34 | prime = next(generator) 35 | while True: 36 | changed = False 37 | for i, n in enumerate(arr): 38 | if n % prime == 0: 39 | arr[i] = n // prime 40 | changed = True 41 | if changed: 42 | ns.append(prime) 43 | else: 44 | break 45 | 46 | if all(n == 1 for n in arr): 47 | return reduce(lambda x, y: x * y, ns) 48 | 49 | 50 | print(get_lcm([n for n in range(1, 21)])) 51 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro006_square_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | 1부터 10까지 자연수를 각각 제곱해 더하면 다음과 같습니다 (제곱의 합). 3 | 4 | 12 + 22 + ... + 102 = 385 5 | 1부터 10을 먼저 더한 다음에 그 결과를 제곱하면 다음과 같습니다 (합의 제곱). 6 | 7 | (1 + 2 + ... + 10)2 = 552 = 3025 8 | 따라서 1부터 10까지 자연수에 대해 "합의 제곱"과 "제곱의 합" 의 차이는 3025 - 385 = 2640 이 됩니다. 9 | 10 | 그러면 1부터 100까지 자연수에 대해 "합의 제곱"과 "제곱의 합"의 차이는 얼마입니까? 11 | """ 12 | 13 | 14 | def square_sum_diff(n): 15 | sum_of_squares = 1 16 | for i in range(2, n+1): 17 | sum_of_squares += i ** 2 18 | 19 | square_of_sum = (n * (n+1) // 2) ** 2 20 | return square_of_sum - sum_of_squares 21 | 22 | print(square_sum_diff(100)) 23 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro007_nth_prime.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | 1 ~ 10 사이의 어떤 수로도 나누어 떨어지는 가장 작은 수는 2520입니다. 4 | 5 | 그러면 1 ~ 20 사이의 어떤 수로도 나누어 떨어지는 가장 작은 수는 얼마입니까? 6 | """ 7 | 8 | def is_prime(n): 9 | if n == 1: 10 | return False 11 | elif n in [2, 3]: 12 | return True 13 | 14 | for d in range(2, int(pow(n, 1/2))+1): 15 | if n % d == 0: 16 | return False 17 | return True 18 | 19 | 20 | def nth_prime_number(nth): 21 | if not isinstance(nth, int) or nth <= 0: 22 | raise ValueError("nth must be an interger over o") 23 | elif nth == 1: 24 | return 2 25 | 26 | count = 2 27 | n = 3 28 | 29 | while count != nth: 30 | n += 2 31 | if is_prime(n): 32 | count += 1 33 | return n 34 | 35 | print(f'{10001:>2d} : {nth_prime_number(10001):>2d}') 36 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro008_largest_substring.py: -------------------------------------------------------------------------------- 1 | """ 2 | 다음은 연속된 1000자리 숫자입니다 (읽기 좋게 50자리씩 잘라놓음). 3 | 4 | 5 | 6 | """ 7 | from functools import reduce 8 | 9 | S = """73167176531330624919225119674426574742355349194934 10 | 96983520312774506326239578318016984801869478851843 11 | 85861560789112949495459501737958331952853208805511 12 | 12540698747158523863050715693290963295227443043557 13 | 66896648950445244523161731856403098711121722383113 14 | 62229893423380308135336276614282806444486645238749 15 | 30358907296290491560440772390713810515859307960866 16 | 70172427121883998797908792274921901699720888093776 17 | 65727333001053367881220235421809751254540594752243 18 | 52584907711670556013604839586446706324415722155397 19 | 53697817977846174064955149290862569321978468622482 20 | 83972241375657056057490261407972968652414535100474 21 | 82166370484403199890008895243450658541227588666881 22 | 16427171479924442928230863465674813919123162824586 23 | 17866458359124566529476545682848912883142607690042 24 | 24219022671055626321111109370544217506941658960408 25 | 07198403850962455444362981230987879927244284909188 26 | 84580156166097919133875499200524063689912560717606 27 | 05886116467109405077541002256983155200055935729725 28 | 71636269561882670428252483600823257530420752963450""" 29 | S = S.replace(' ', '') 30 | S = S.replace('\n', '') 31 | 32 | def largest_substring(string, length, func): 33 | return func(reduce(lambda x, y: int(x) * int(y), string[i:i+length]) for i in 34 | range(len(string)-length+1)) 35 | 36 | print(largest_substring(S, 5, max)) 37 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro009_pythagoras.py: -------------------------------------------------------------------------------- 1 | """ 2 | 세 자연수 a, b, c 가 피타고라스 정리 a2 + b2 = c2 를 만족하면 피타고라스 수라고 부릅니다 (여기서 a 3 | < b < c ). 4 | 예를 들면 3**2 + 4**2 = 9 + 16 = 25 = 5**2이므로 3, 4, 5는 피타고라스 수입니다. 5 | 6 | a + b + c = 1000 인 피타고라스 수 a, b, c는 한 가지 뿐입니다. 이 때, a × b × c 는 얼마입니까? 7 | 8 | 9 | Date: 2018/03/20 10 | """ 11 | 12 | 13 | diff = 1 14 | while True: 15 | a, b = 1, 1 + diff 16 | while a + b < 1000: 17 | c = (a**2 + b**2) ** (1/2) 18 | if a + b + c == 1000: 19 | print(a * b * c) 20 | else: 21 | a += 1 22 | b += 1 23 | diff += 1 24 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro010_prime_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | 10 이하의 소수를 모두 더하면 2 + 3 + 5 + 7 = 17 이 됩니다. 3 | 4 | 이백만(2,000,000) 이하 소수의 합은 얼마입니까? 5 | """ 6 | 7 | 8 | def is_prime(n): 9 | if n == 1: 10 | return False 11 | elif n in [2, 3]: 12 | return True 13 | 14 | for d in range(2, int(pow(n, 1/2))+1): 15 | if n % d == 0: 16 | return False 17 | return True 18 | 19 | 20 | def prime_number_generator(): 21 | n = 3 22 | yield 2 23 | yield 3 24 | 25 | while True: 26 | n += 2 27 | if is_prime(n): 28 | yield n 29 | 30 | 31 | prime_sum = 0 32 | p_now = 0 33 | gen = prime_number_generator() 34 | 35 | while p_now <= 2000000: 36 | prime_sum += p_now 37 | p_now = next(gen) 38 | 39 | print(prime_sum) 40 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro011_max_multiple_grid.py: -------------------------------------------------------------------------------- 1 | """No.11 - 격자 속 최대의 연속값 구하기. 2 | 3 | 4 | 아래와 같은 20×20 격자가 있습니다. 5 | 6 | 08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 7 | 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 8 | 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 9 | 52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91 10 | 22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80 11 | 24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50 12 | 32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70 13 | 67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21 14 | 24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72 15 | 21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95 16 | 78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92 17 | 16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57 18 | 86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58 19 | 19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40 20 | 04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66 21 | 88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69 22 | 04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36 23 | 20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16 24 | 20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54 25 | 01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48 26 | 27 | 28 | 위에서 대각선 방향으로 연속된 붉은 숫자 네 개의 곱은 26 × 63 × 78 × 14 = 1788696 입니다. 29 | 그러면 수평, 수직, 또는 대각선 방향으로 연속된 숫자 네 개의 곱 중 최대값은 얼마입니까? 30 | """ 31 | 32 | 33 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro012_triangle_number.py: -------------------------------------------------------------------------------- 1 | """ 2 | 1부터 n까지의 자연수를 차례로 더하여 구해진 값을 삼각수라고 합니다. 3 | 예를 들어 7번째 삼각수는 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28이 됩니다. 4 | 이런 식으로 삼각수를 구해 나가면 다음과 같습니다. 5 | 6 | 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ... 7 | 이 삼각수들의 약수를 구해봅시다. 8 | 9 | 1 : 1 10 | 3 : 1, 3 11 | 6 : 1, 2, 3, 6 12 | 10: 1, 2, 5, 10 13 | 15: 1, 3, 5, 15 14 | 21: 1, 3, 7, 21 15 | 28: 1, 2, 4, 7, 14, 28 16 | 17 | 위에서 보듯이, 5개 이상의 약수를 갖는 첫번째 삼각수는 28입니다. 18 | 그러면 500개 이상의 약수를 갖는 가장 작은 삼각수는 얼마입니까? 19 | """ 20 | from functools import reduce 21 | 22 | 23 | def count_divisors(n): 24 | divisor = 2 25 | divisor_list = [] 26 | total_count = 1 27 | 28 | while n > 1: 29 | d_count = 0 30 | 31 | while n % divisor == 0: 32 | n //= divisor 33 | d_count += 1 34 | 35 | divisor += 1 36 | total_count *= (d_count + 1) 37 | 38 | return total_count 39 | 40 | 41 | for i in range(1, 11): 42 | print(i, count_divisors(i)) 43 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro014_max_collaz.py: -------------------------------------------------------------------------------- 1 | """ 2 | 양의 정수 n에 대하여, 다음과 같은 계산 과정을 반복하기로 합니다. 3 | 4 | n → n / 2 (n이 짝수일 때) 5 | n → 3 n + 1 (n이 홀수일 때) 6 | 7 | 13에 대하여 위의 규칙을 적용해보면 아래처럼 10번의 과정을 통해 1이 됩니다. 8 | 9 | 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 10 | 아직 증명은 되지 않았지만, 이런 과정을 거치면 어떤 수로 시작해도 마지막에는 1로 끝나리라 생각됩니다. 11 | (역주: 이것은 콜라츠 추측 Collatz Conjecture이라고 하며, 이런 수들을 우박수 hailstone sequence라 12 | 부르기도 합니다) 13 | 14 | 그러면, 백만(1,000,000) 이하의 수로 시작했을 때 1까지 도달하는데 가장 긴 과정을 거치는 숫자는 15 | 얼마입니까? 16 | 17 | 참고: 계산 과정 도중에는 숫자가 백만을 넘어가도 괜찮습니다. 18 | """ 19 | 20 | 21 | def get_collaz(n): 22 | max_tuple = (2, 0) 23 | for i in range(2, n+1): 24 | ori = i 25 | count = 0 26 | while i > 1: 27 | if i % 2: 28 | i = i * 3 + 1 29 | else: 30 | i //= 2 31 | print(f"{ori:>4d} : {count:>4d}") 32 | max_tuple = (ori, count) if count > max_tuple[1] else max_tuple 33 | return max_tuple 34 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro015_path_to_lattice.py: -------------------------------------------------------------------------------- 1 | """ 2 | 2 × 2 격자의 왼쪽 위 모서리에서 출발하여 오른쪽 아래 모서리까지 도달하는 길은 모두 3 | 6가지가 있습니다 (거슬러 가지는 않기로 합니다). 4 | 5 | 6 | 그러면 20 × 20 격자에는 모두 몇 개의 경로가 있습니까? 7 | """ 8 | 9 | 10 | def factorial(n, _cache={1:1, 2:2}): 11 | if n in _cache: 12 | return _cache[n] 13 | else: 14 | value = n * factorial(n-1) 15 | _cache[n] = value 16 | return value 17 | 18 | 19 | def way_lattice(nth): 20 | return factorial(2 * nth) // factorial(nth) // factorial(nth) 21 | 22 | 23 | print(way_lattice(20)) 24 | 25 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro016_sum_digit.py: -------------------------------------------------------------------------------- 1 | """ 2 | 215 = 32768 의 각 자리수를 더하면 3 + 2 + 7 + 6 + 8 = 26 입니다. 3 | 4 | 2 ^ 1000의 각 자리수를 모두 더하면 얼마입니까? 5 | """ 6 | 7 | 8 | n = 2 ** 1000 9 | d_sum = 0 10 | 11 | while n: 12 | d_sum += n % 10 13 | n //= 10 14 | 15 | print(d_sum) 16 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro017_length_of_digit.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 1부터 5까지의 숫자를 영어로 쓰면 one, two, three, four, five 이고, 4 | 각 단어의 길이를 더하면 3 + 3 + 5 + 4 + 4 = 19 이므로 사용된 글자는 모두 19개입니다. 5 | 6 | 1부터 1,000까지 영어로 썼을 때는 모두 몇 개의 글자를 사용해야 할까요? 7 | 8 | 참고: 빈 칸이나 하이픈('-')은 셈에서 제외하며, 단어 사이의 and 는 셈에 넣습니다. 9 | 예를 들어 342를 영어로 쓰면 three hundred and forty-two 가 되어서 23 글자, 10 | 115 = one hundred and fifteen 의 경우에는 20 글자가 됩니다. 11 | """ 12 | 13 | 14 | TABLE = {0: 0, 1: len('one'), 2: len('two'), 3: len('three'), 4: len('four'), 5: len('five'), 15 | 6: len('six'), 7: len('seven'), 8: len('eight'), 9: len('nine'), 10: len('ten'), 16 | 11: len('eleven'), 12: len('twelve'), 13: len('thirteen'), 14: len('fourteen'), 15: 17 | len('fifteen'), 18 | 16: len('sixteen'), 17: len('seventeen'), 18: len('eighteen'), 19: len('nineteen'), 20: 19 | len('twenty'), 20 | 30: len('thirty'), 40: len('forty'), 50: len('fifty'), 60: len('sixty'), 70: 21 | len('seventy'), 22 | 80: len('eighty'), 90: len('ninety'), 'hund': len('hundred'),} 23 | 24 | 25 | def digit_len(n): 26 | if n > 999: 27 | raise ValueError("n Should be an integer UNDER 1000") 28 | 29 | a = n // 100 30 | bc = n % 100 31 | b = bc // 10 32 | c = bc % 10 33 | r = 0 34 | 35 | if n in TABLE: 36 | return TABLE[n] 37 | if a: 38 | r += (TABLE[a] + TABLE['hund']) 39 | if a and bc: 40 | r += len('and') 41 | if bc in TABLE: 42 | r += TABLE[bc] 43 | else: 44 | r += (TABLE[b*10] + TABLE[c]) 45 | 46 | return r 47 | 48 | 49 | n = 1 50 | s = 0 51 | while n <= 999: 52 | s += digit_len(n) 53 | n += 1 54 | 55 | s += len('onethousand') 56 | print(s) 57 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro018_max_line_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | 다음과 같이 삼각형 모양으로 숫자를 배열했습니다. 3 | 4 | 3 5 | 7 4 6 | 2 4 6 7 | 8 5 9 3 8 | 9 | 삼각형의 꼭대기부터 아래쪽으로 인접한 숫자를 찾아 내려가면서 합을 구하면, 위의 그림처럼 3 + 7 + 4 + 10 | 9 = 23 이 가장 큰 합을 갖는 경로가 됩니다. 11 | 12 | 다음 삼각형에서 합이 최대가 되는 경로를 찾아서 그 합을 구하세요. 13 | """ 14 | from pprint import pprint 15 | 16 | 17 | n = 15 18 | p = [[0 for _ in range(n+1)] for _ in range(n+1)] 19 | cum_p = p.copy() 20 | s = """75 21 | 95 64 22 | 17 47 82 23 | 18 35 87 10 24 | 20 04 82 47 65 25 | 19 01 23 75 03 34 26 | 88 02 77 73 07 63 67 27 | 99 65 04 28 06 16 70 92 28 | 41 41 26 56 83 40 80 70 33 29 | 41 48 72 33 47 32 37 16 94 29 30 | 53 71 44 65 25 43 91 52 97 51 14 31 | 70 11 33 28 77 73 17 78 39 68 17 57 32 | 91 71 52 38 17 14 91 43 58 50 27 29 48 33 | 63 66 04 68 89 53 67 30 73 16 69 87 40 31 34 | 04 62 98 27 23 09 70 98 73 93 38 53 60 04 23""" 35 | 36 | 37 | s = [[0] + line.split(' ') for line in s.split('\n')] 38 | s.insert(0, [0]) 39 | 40 | for r, line in enumerate(s): 41 | for c, n in enumerate(line): 42 | if n: 43 | p[r][c] = int(n) 44 | 45 | pprint(p) 46 | 47 | for r in range(1, 15+1): 48 | for c in range(1, 15+1): 49 | cum_p[r][c] = max(cum_p[r-1][c-1], cum_p[r-1][c]) + p[r][c] 50 | 51 | print(max(cum_p[-1])) 52 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro019_monday.py: -------------------------------------------------------------------------------- 1 | """ 2 | 다음은 달력에 관한 몇 가지 일반적인 정보입니다. 3 | 4 | * 1900년 1월 1일은 월요일이다. 5 | * 4월, 6월, 9월, 11월은 30일까지 있고, 1월, 3월, 5월, 7월, 8월, 10월, 12월은 31일까지 있다. 6 | * 2월은 28일이지만, 윤년에는 29일까지 있다. 7 | * 윤년은 연도를 4로 나누어 떨어지는 해를 말한다. 8 | * 하지만 100으로 나누어 떨어지지 않는 해는 윤년이 아니며, 400으로 나누어 떨어지면 윤년이다. 9 | 10 | 20세기(1901년 1월 1일 ~ 2000년 12월 31일)에서, 매월 1일이 일요일인 경우는 총 몇 번입니까? 11 | """ 12 | 13 | 14 | WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] 15 | MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 16 | CUM_MONTH_DAYS = [sum(MONTH_DAYS[0:i]) for i in range(12)] 17 | CUM_MONTH_DAYS = [d % 7 for d in CUM_MONTH_DAYS] 18 | CUM_MONTH_DAYS.insert(0, 0) 19 | YEAR_DELTA = 365 % 7 20 | 21 | 22 | def is_leap(year): 23 | return year % 400 == 0 or year % 4 == 0 and year % 100 != 0 24 | 25 | 26 | def weekday(year, month, day): 27 | total_day = 0 28 | 29 | for y in range(1900, year): 30 | total_day += YEAR_DELTA if not is_leap(y) else (YEAR_DELTA+1) 31 | 32 | total_day += CUM_MONTH_DAYS[month] 33 | if is_leap(year) and month >= 3: 34 | total_day += 1 35 | total_day += (day - 1) 36 | total_day %= 7 37 | 38 | return WEEKDAYS[total_day] 39 | 40 | 41 | count = 0 42 | for year in range(1901, 2000+1): 43 | for month in range(1, 12+1): 44 | if weekday(year, month, 1) == 'Sun': 45 | count += 1 46 | 47 | print(count) 48 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro020_sum_digit2.py: -------------------------------------------------------------------------------- 1 | """ 2 | n! 이라는 표기법은 n × (n − 1) × ... × 3 × 2 × 1을 뜻합니다. 3 | 4 | 예를 들자면 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800 이 되는데, 5 | 여기서 10!의 각 자리수를 더해 보면 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27 입니다. 6 | 7 | 100! 의 자리수를 모두 더하면 얼마입니까? 8 | """ 9 | 10 | 11 | def factorial(n, _cache={1: 1, 2: 2}): 12 | if n in _cache: 13 | return _cache[n] 14 | 15 | else: 16 | return n * factorial(n-1) 17 | 18 | fact_100 = factorial(100) 19 | d_sum = 0 20 | 21 | while fact_100: 22 | d_sum += fact_100 % 10 23 | fact_100 //= 10 24 | 25 | print(d_sum) 26 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro021_familiar_number.py: -------------------------------------------------------------------------------- 1 | """ 2 | n의 약수들 중에서 자신을 제외한 것의 합을 d(n)으로 정의했을 때, 3 | 서로 다른 두 정수 a, b에 대하여 d(a) = b 이고 d(b) = a 이면 4 | a, b는 친화쌍이라 하고 a와 b를 각각 친화수(우애수)라고 합니다. 5 | 6 | 예를 들어 220의 약수는 자신을 제외하면 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 이므로 그 합은 d(220) 7 | = 284 입니다. 8 | 또 284의 약수는 자신을 제외하면 1, 2, 4, 71, 142 이므로 d(284) = 220 입니다. 9 | 따라서 220과 284는 친화쌍이 됩니다. 10 | 11 | 10000 이하의 친화수들을 모두 찾아서 그 합을 구하세요. 12 | """ 13 | def divisor_sum(n): 14 | if n == 1: 15 | return 0 16 | 17 | s = 1 18 | 19 | for d in range(2, int(n ** (1/2))+1): 20 | if n % d == 0: 21 | s += d 22 | s += n // d 23 | 24 | if d == n // d: 25 | s -= d 26 | return s 27 | 28 | 29 | SIZE = 10000 30 | checker = [0] * (SIZE+1) 31 | 32 | for n in range(2, SIZE+1): 33 | friend = divisor_sum(n) 34 | if not checker[n] and friend != n and divisor_sum(friend) == n: 35 | checker[n] = 1 36 | checker[friend] = 1 37 | 38 | 39 | print(sum(i for i, n in enumerate(checker) if n)) 40 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro022_name_value.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 여기 5천개 이상의 영문 이름들이 들어있는 46KB짜리 텍스트 파일 names.txt 이 있습니다 (우클릭해서 4 | 다운로드 받으세요). 5 | 이제 각 이름에 대해서 아래와 같은 방법으로 점수를 매기고자 합니다. 6 | 7 | 먼저 모든 이름을 알파벳 순으로 정렬합니다. 8 | 각 이름에 대해서, 그 이름을 이루는 알파벳에 해당하는 숫자(A=1, B=2, ..., Z=26)를 모두 더합니다. 9 | 여기에 이 이름의 순번을 곱합니다. 10 | 예를 들어 "COLIN"의 경우, 알파벳에 해당하는 숫자는 3, 15, 12, 9, 14이므로 합이 53, 그리고 정렬했을 11 | 때 938번째에 오므로 최종 점수는 938 × 53 = 49714가 됩니다. 12 | 13 | names.txt에 들어있는 모든 이름의 점수를 계산해서 더하면 얼마입니까? 14 | """ 15 | from string import ascii_uppercase as CAPITAL 16 | 17 | 18 | CAPITAL = '"' + CAPITAL 19 | with open('names.txt') as fd: 20 | names = fd.read() 21 | names = names.split(',') 22 | names.sort() 23 | score = 0 24 | 25 | 26 | for i, name in enumerate(names, 1): 27 | for c in name: 28 | score += i * CAPITAL.index(c) 29 | 30 | print(score) 31 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro023_abun_n_sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | 자신을 제외한 약수(진약수)를 모두 더하면 자기 자신이 되는 수를 완전수라고 합니다. 3 | 예를 들어 28은 1 + 2 + 4 + 7 + 14 = 28 이므로 완전수입니다. 4 | 또, 진약수의 합이 자신보다 작으면 부족수, 자신보다 클 때는 초과수라고 합니다. 5 | 6 | 12는 1 + 2 + 3 + 4 + 6 = 16 > 12 로서 초과수 중에서는 가장 작습니다. 7 | 따라서 초과수 두 개의 합으로 나타낼 수 있는 수 중 가장 작은 수는 24 (= 12 + 12) 입니다. 8 | 9 | 해석학적인 방법을 사용하면, 28123을 넘는 모든 정수는 두 초과수의 합으로 표현 가능함을 보일 수가 10 | 있습니다. 11 | 두 초과수의 합으로 나타낼 수 없는 가장 큰 수는 실제로는 이 한계값보다 작지만, 해석학적인 방법으로는 12 | 더 이상 이 한계값을 낮출 수 없다고 합니다. 13 | 14 | 그렇다면, 초과수 두 개의 합으로 나타낼 수 없는 모든 양의 정수의 합은 얼마입니까? 15 | """ 16 | import time 17 | 18 | 19 | start = time.time() 20 | checker = [1 for _ in range(28123*2+1)] 21 | abun_list = [] 22 | 23 | 24 | def is_abundant(n): 25 | s = 1 26 | inted_sqrt = int(n**(1/2)) 27 | for d in range(2, inted_sqrt+1): 28 | if n % d == 0: 29 | s += d 30 | s += n // d 31 | if inted_sqrt ** 2 == n: 32 | s -= inted_sqrt 33 | 34 | return True if s > n else False 35 | 36 | 37 | n = 2 38 | while n <= 28123: 39 | if is_abundant(n): 40 | abun_list.append(n) 41 | n += 1 42 | 43 | 44 | length = len(abun_list) 45 | for i in range(length): 46 | for j in range(i, length): 47 | checker[abun_list[i] + abun_list[j]] = 0 48 | 49 | 50 | s = 0 51 | for i, n in enumerate(checker[:28123+1]): 52 | if n: 53 | s += i 54 | 55 | print(s) 56 | end = time.time() 57 | print(end - start) 58 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro024_lexicographic_sequence.py: -------------------------------------------------------------------------------- 1 | from math import factorial 2 | 3 | 4 | def get_nth_sequence(sequence, nth): 5 | S = len(sequence) 6 | 7 | if factorial(S) < nth: 8 | return -1 9 | 10 | nth -= 1 11 | used = [0] * S 12 | sequence = list(sequence) 13 | ret = '' 14 | 15 | for i in range(1, S+1): 16 | count = 0 17 | while nth >= factorial(S - i): 18 | count += 1 19 | nth -= factorial(S - i) 20 | 21 | for j in range(S): 22 | if not used[j]: 23 | if count != 0: 24 | count -= 1 25 | else: 26 | use_this = j 27 | break 28 | used[use_this] = 1 29 | ret += str(sequence[use_this]) 30 | 31 | return ret 32 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro025_fibo_d.py: -------------------------------------------------------------------------------- 1 | """ 2 | 피보나치 수열은 아래와 같은 점화식으로 정의됩니다. 3 | 4 | Fn = Fn-1 + Fn-2 (단, F1 = 1, F2 = 1). 5 | 이에 따라 수열을 12번째 항까지 차례대로 계산하면 다음과 같습니다. 6 | 7 | F1 = 1 8 | F2 = 1 9 | F3 = 2 10 | F4 = 3 11 | F5 = 5 12 | F6 = 8 13 | F7 = 13 14 | F8 = 21 15 | F9 = 34 16 | F10 = 55 17 | F11 = 89 18 | F12 = 144 19 | 수열의 값은 F12에서 처음으로 3자리가 됩니다. 20 | 21 | 피보나치 수열에서 값이 처음으로 1000자리가 되는 것은 몇번째 항입니까? 22 | """ 23 | def d(n): 24 | count = 0 25 | while n: 26 | count += 1 27 | n //= 10 28 | return count 29 | 30 | 31 | def fibo_nth(n): 32 | a, b = 1, 1 33 | for _ in range(n-1): 34 | a, b = b, a + b 35 | return a 36 | 37 | 38 | n = 1 39 | while True: 40 | if d(fibo_nth(n)) >= 1000: 41 | print(n) 42 | break 43 | n += 1 44 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro026_longest_recurring_sequences.py: -------------------------------------------------------------------------------- 1 | def get_cycle_len(d): 2 | n = 1 3 | remains = [0] * d 4 | first_checked = {} 5 | sequences = [] 6 | 7 | i = 0 8 | while True: 9 | share, remain = divmod(n, d) 10 | 11 | if not remain: 12 | return 0 13 | elif remains[remain]: 14 | length = i - first_checked[remain] 15 | sequences.append(share) 16 | # return sequences[-length:] 17 | return length 18 | else: 19 | first_checked[remain] = i 20 | remains[remain] = 1 21 | sequences.append(share) 22 | n = remain * 10 23 | i += 1 24 | 25 | 26 | if __name__ == '__main__': 27 | SIZE = 1000 28 | ans = -1 29 | tmp_max = -1 30 | 31 | for n in range(1, SIZE+1): 32 | if get_cycle_len(n) > tmp_max: 33 | ans = n 34 | tmp_max = get_cycle_len(n) 35 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro027_euler_equation.py: -------------------------------------------------------------------------------- 1 | """ 2 | 오일러는 다음과 같은 멋진 2차식을 제시했습니다. 3 | 4 | n2 + n + 41 5 | 이 식의 n에다 0부터 39 사이의 숫자를 넣으면, 그 결과는 모두 소수가 됩니다. 6 | 하지만 n = 40일 때의 값 402 + 40 + 41 은 40×(40 + 1) + 41 이므로 41로 나누어지고, n = 41일 때 역시 7 | 412 + 41 + 41 이므로 소수가 아닙니다. 8 | 9 | 컴퓨터의 발전에 힘입어 n2 − 79n + 1601 이라는 엄청난 2차식이 발견되었는데, 이것은 n이 0에서 79 10 | 사이일 때 모두 80개의 소수를 만들어냅니다. 이 식의 계수의 곱은 -79 × 1601 = -126479가 됩니다. 11 | 12 | 아래와 같은 모양의 2차식이 있다고 가정했을 때, 13 | 14 | n2 + an + b (단 | a | < 1000, | b | < 1000) 15 | 0부터 시작하는 연속된 n에 대해 가장 많은 소수를 만들어내는 2차식을 찾아서, 그 계수 a와 b의 곱을 16 | 구하세요. 17 | """ 18 | import time 19 | 20 | 21 | def is_prime(n): 22 | if n in [2, 3]: 23 | return True 24 | elif n <= 1: 25 | return False 26 | 27 | for d in range(2, int(n ** (1/2) + 1)): 28 | if n % d == 0: 29 | return False 30 | return True 31 | 32 | 33 | def euler_equation(): 34 | max_a = 0 35 | max_b = 0 36 | count = 0 37 | 38 | for a in range(-999, 999+1): 39 | for b in range(-999, 999+1): 40 | tmp_n = 0 41 | while is_prime(tmp_n**2 + a*tmp_n + b): 42 | tmp_n += 1 43 | if count < tmp_n: 44 | max_a = a 45 | max_b = b 46 | count = tmp_n 47 | return max_a * max_b 48 | 49 | 50 | c = time.time() 51 | print(euler_equation()) 52 | e = time.time() 53 | print(float(e)-float(c)) 54 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro028_spiral_sums.py: -------------------------------------------------------------------------------- 1 | def get_spiral_sums(n): 2 | ans = 1 3 | times = (n - 1) // 2 4 | d = 2 5 | tmp = 1 6 | 7 | for _ in range(times): 8 | for _ in range(4): 9 | tmp += d 10 | ans += tmp 11 | d += 2 12 | 13 | return ans 14 | 15 | 16 | if __name__ == '__main__': 17 | print(get_spiral_sums(1001)) 18 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro029_all_squares.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | 2 ≤ a ≤ 5 이고 2 ≤ b ≤ 5인 두 정수 a, b로 만들 수 있는 a ^ b의 모든 조합을 구하면 다음과 같습니다. 4 | 5 | 2^2=4, 2^3=8, 2^4=16, 2^5=32 6 | 3^2=9, 3^3=27, 3^4=81, 3^5=243 7 | 4^2=16, 4^3=64, 4^4=256, 4^5=1024 8 | 5^2=25, 5^3=125, 5^4=625, 5^5=3125 9 | 10 | 여기서 중복된 것을 빼고 크기 순으로 나열하면 아래와 같은 15개의 숫자가 됩니다. 11 | 12 | 4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125 13 | 14 | 그러면, 2 ≤ a ≤ 100 이고 2 ≤ b ≤ 100인 a, b를 가지고 만들 수 있는 a ^ b는 중복을 제외하면 모두 몇 15 | 개입니까? 16 | """ 17 | from pprint import pprint 18 | 19 | 20 | # def divisor_gen(n): 21 | # r = [] 22 | # for d in range(n//2, 1, -1): 23 | # if n % d == 0: 24 | # r.append(d) 25 | # return r 26 | 27 | 28 | # dynamic table initialization 29 | # dt = [[1 for _ in range(101)] for _ in range(101)] 30 | # for i in range(2): 31 | # dt[i] = [0 for _ in range(101)] 32 | # for j in range(101): 33 | # dt[j][i] = 0 34 | 35 | 36 | # Calculate 37 | # def square_sum(n): 38 | # dt = [[1 for _ in range(n+1)] for _ in range(n+1)] 39 | # for i in range(2): 40 | # dt[i] = [0 for _ in range(n+1)] 41 | # for j in range(n+1): 42 | # dt[j][i] = 0 43 | 44 | # for a in range(2, n+1): 45 | # for b in range(n, 1, -1): 46 | # for b in range(2, n+1): 47 | # if dt[a][b]: 48 | # divisors = divisor_gen(b) 49 | # for d in divisors: 50 | # c = b // d 51 | # if a ** c <= n: 52 | # dt[a**c][d] = 0 53 | # else: 54 | # break 55 | 56 | # print(sum(sum(line) for line in dt)) 57 | # return None 58 | 59 | 60 | # square_sum(100) 61 | 62 | dt = [] 63 | for a in range(2, 100+1): 64 | for b in range(2, 100+1): 65 | if a ** b not in dt: 66 | dt.append(a**b) 67 | 68 | print(len(dt)) 69 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro030_get_self_sum.py: -------------------------------------------------------------------------------- 1 | def sum_squared_digits(n, d): 2 | ans = 0 3 | while n: 4 | n, rest = divmod(n, 10) 5 | ans += (rest ** d) 6 | 7 | return ans 8 | 9 | 10 | if __name__ == '__main__': 11 | MAX = 10 ** 6 12 | ans = 0 13 | 14 | for n in range(10, MAX): 15 | if sum_squared_digits(n, 5) == n: 16 | ans += n 17 | 18 | print(ans) 19 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro031_combinate_2pounds.py: -------------------------------------------------------------------------------- 1 | def get_number_ways(num): 2 | UNITS = [1, 2, 5, 10, 20, 50, 100, 200] 3 | U = len(UNITS) 4 | ans = 0 5 | num *= 100 # 1 pound = 100 pence 6 | # '달과 6펜스'가 생각남. ㅇㅈ? 7 | 8 | cache = [[0] * (num + 1) for _ in range(U+1)] 9 | for u in range(U+1): 10 | cache[u][0] = 1 11 | 12 | UNITS = [0] + UNITS 13 | 14 | for u in range(1, U+1): 15 | for n in range(num+1): 16 | if UNITS[u] > n: 17 | break 18 | 19 | cache[u][n] = cache[u-1][n] + (cache[u][n-UNITS[u]] if n - UNITS[u] >= 0 else 0) 20 | 21 | return cache 22 | 23 | 24 | if __name__ == '__main__': 25 | print(get_number_ways(2)) 26 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro032_pandigital_sum.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations 2 | 3 | 4 | c_set = set() 5 | 6 | 7 | def to_number(arr): 8 | ans = 0 9 | arr = arr[::-1] 10 | 11 | for i in range(len(arr)): 12 | ans *= 10 13 | ans += arr[i] 14 | 15 | return ans 16 | 17 | 18 | for perm in permutations(range(1, 10)): 19 | for i in range(1, 3): 20 | a, b, c = perm[:i], perm[i:5], perm[5:] 21 | a, b, c = to_number(a), to_number(b), to_number(c) 22 | c = sorted(str(c)) 23 | 24 | c_cand = a * b 25 | if sorted(str(c_cand)) == c and c_cand not in c_set: 26 | c_set.add(c_cand) 27 | 28 | 29 | print(sum(c_set)) 30 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro033_weird_reduction.py: -------------------------------------------------------------------------------- 1 | # 2. Return whether a fractions number can be reduced in an weird way. 2 | def can_weird_reduce(dividend, divisor): 3 | dividend, divisor = str(dividend), str(divisor) 4 | 5 | for a in str(dividend): 6 | for b in str(divisor): 7 | if a == b and a != '0' and b != '0': 8 | p1 = int(dividend[1-dividend.index(a)]) 9 | p2 = int(divisor[1-divisor.index(b)]) 10 | if p1 != 0 and int(divisor) / int(dividend) == p2 / p1: 11 | return True 12 | return False 13 | 14 | 15 | fractions = [] 16 | 17 | # 1. Combinate over all two digit fractions less than 1. 18 | for a in range(10, 100): 19 | for b in range(a+1, 100): 20 | if can_weird_reduce(a, b): 21 | fractions.append((a, b)) 22 | 23 | if len(fractions) == 4: 24 | break 25 | 26 | 27 | # 3. Calculate the answer 28 | ans = 1 29 | 30 | for a, b in fractions: 31 | ans *= (b / a) 32 | 33 | 34 | print(int(ans)) 35 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro034_sum_digits_factorial.py: -------------------------------------------------------------------------------- 1 | from math import factorial 2 | 3 | 4 | def sum_digits_factorial(n): 5 | ret = 0 6 | 7 | while n: 8 | n, rest = divmod(n, 10) 9 | ret += factorial(rest) 10 | 11 | return ret 12 | 13 | 14 | if __name__ == '__main__': 15 | count = 0 16 | 17 | for n in range(10, 10 ** 7): 18 | if n == sum_digits_factorial(n): 19 | count += 1 20 | 21 | print(count) 22 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro035_circular_prime.py: -------------------------------------------------------------------------------- 1 | from math import log10 2 | 3 | 4 | SIZE = 10 ** 6 5 | sieve = [1] * (SIZE + 1) 6 | sieve[0] = sieve[1] = 0 7 | 8 | SQRT_SIZE = int(SIZE ** (1/2)) 9 | 10 | for i in range(2, SQRT_SIZE+1): 11 | if sieve[i]: 12 | for j in range(i*i, SIZE+1, i): 13 | sieve[j] = 0 14 | 15 | 16 | def is_circular_prime(n): 17 | global sieve 18 | 19 | log = int(log10(n)) 20 | for _ in range(log+1): 21 | if not sieve[n]: 22 | return False 23 | 24 | n, rest = divmod(n, 10) 25 | n += rest * 10 ** log 26 | 27 | return True 28 | 29 | 30 | if __name__ == '__main__': 31 | count = 0 32 | 33 | for n in range(2, SIZE+1): 34 | if is_circular_prime(n): 35 | count += 1 36 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro036_sum_of_palindromes_in_base_10_and_2.py: -------------------------------------------------------------------------------- 1 | def is_palindrome_str(strng): 2 | if len(strng) <= 1: 3 | return True 4 | 5 | return False if strng[0] != strng[-1] else is_palindrome_str(strng[1:-1]) 6 | 7 | 8 | if __name__ == '__main__': 9 | SIZE = 10 ** 6 10 | ret = 0 11 | 12 | for n in range(1, SIZE+1): 13 | bin_n = bin(n)[2:] 14 | 15 | if is_palindrome_str(bin_n) & is_palindrome_str(str(n)): 16 | ret += n 17 | 18 | print(n) 19 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro037_prime_always.py: -------------------------------------------------------------------------------- 1 | from math import log10 2 | 3 | 4 | def is_prime(n): 5 | if n <= 1: 6 | return False 7 | if n == 2: 8 | return True 9 | elif n % 2 == 0: 10 | return False 11 | 12 | for d in range(3, int(n ** (1/2))+1, 2): 13 | if n % d == 0: 14 | return False 15 | 16 | return True 17 | 18 | 19 | def move_shift_once(n, is_left=True): 20 | if is_left: 21 | log = int(log10(n)) 22 | return n % (10 ** log) 23 | else: 24 | return n // 10 25 | 26 | 27 | if __name__ == '__main__': 28 | primes = [] 29 | n = 11 30 | 31 | while len(primes) < 11: 32 | if is_prime(n): 33 | is_all_prime = True 34 | log = int(log10(n)) 35 | left_shifted = right_shifted = n 36 | 37 | for _ in range(log): 38 | left_shifted = move_shift_once(left_shifted) 39 | right_shifted = move_shift_once(right_shifted, is_left=False) 40 | if not is_prime(left_shifted) or not is_prime(right_shifted): 41 | is_all_prime = False 42 | break 43 | 44 | if is_all_prime: 45 | primes.append(n) 46 | 47 | n += 2 48 | 49 | 50 | print(sum(primes)) 51 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro038_largest_pandigital_number.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | def is_pandigital(num, MIN_V, MAX_V): 5 | counter = Counter(str(num)) 6 | 7 | if all(counter[str(n)] >= 1 for n in range(MIN_V, MAX_V+1)): 8 | return True 9 | else: 10 | return False 11 | 12 | 13 | def multiply_from_1(n, MIN_LENGTH): 14 | ret = '' 15 | m = 1 16 | 17 | while len(ret) < MIN_LENGTH: 18 | ret += str(n * m) 19 | m += 1 20 | 21 | return int(ret) 22 | 23 | 24 | if __name__ == '__main__': 25 | ans = -1 26 | for n in range(1, 10 ** 5): 27 | cand = multiply_from_1(n, 9) 28 | if is_pandigital(cand, 1, 9) and len(str(cand)) == 9: 29 | ans = max(ans, int(cand)) 30 | 31 | print(ans) 32 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro039_max_number_of_right_triangles.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | MAX_CIRCUMFERENCE = 1000 5 | 6 | 7 | counter = Counter() 8 | 9 | for a in range(1, MAX_CIRCUMFERENCE // 3 + 1): 10 | for b in range(a+1, MAX_CIRCUMFERENCE // 2 + 1): 11 | c = (a ** 2 + b ** 2) ** (1 / 2) 12 | if c.is_integer() and (a + b + c) <= MAX_CIRCUMFERENCE: 13 | counter[int(a+b+c)] += 1 14 | 15 | 16 | print(counter.most_common()[0]) 17 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro040_find_nth_digit.py: -------------------------------------------------------------------------------- 1 | MAX_DIGIT = 10 ** 6 2 | 3 | digits_lens = [0] 4 | digits_lens_cum = [1] 5 | e = 1 6 | 7 | while digits_lens[-1] <= MAX_DIGIT: 8 | digits_lens.append(e * 9 * (10 ** (e-1))) 9 | digits_lens_cum.append(digits_lens_cum[-1] + digits_lens[-1]) 10 | e += 1 11 | 12 | 13 | def find_nth_digit(nth): 14 | for e in range(len(digits_lens_cum)): 15 | if digits_lens_cum[e] <= nth < digits_lens_cum[e+1]: 16 | break 17 | 18 | d = e + 1 19 | start = 10 ** e 20 | cnt, rest = divmod(nth - digits_lens_cum[e], d) 21 | last = start + cnt 22 | return str(last)[rest] 23 | 24 | 25 | if __name__ == '__main__': 26 | ans = 1 27 | for e in range(7): 28 | ans *= int(find_nth_digit(10 ** e)) 29 | 30 | print(ans) 31 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro041_largest_prime_pandigital_number.py: -------------------------------------------------------------------------------- 1 | def is_prime(n): 2 | if n == 1: 3 | return False 4 | elif n == 2: 5 | return True 6 | elif n % 2 == 0: 7 | return False 8 | 9 | for d in range(3, int(n ** (1/2))+1, 2): 10 | if n % d == 0: 11 | return False 12 | 13 | return True 14 | 15 | 16 | def permutations(digit): 17 | used = [0] * (digit + 1) 18 | used[0] = 1 19 | all_nums = [] 20 | 21 | def generate(tmp, used): 22 | nonlocal all_nums 23 | if all(used): 24 | all_nums.append(tmp) 25 | 26 | for n in range(1, digit+1): 27 | if not used[n]: 28 | used[n] = 1 29 | generate(tmp * 10 + n, used) 30 | used[n] = 0 31 | 32 | generate(0, used) 33 | return all_nums 34 | 35 | 36 | if __name__ == "__main__": 37 | found = False 38 | largest = -1 39 | 40 | for l in range(9, 0, -1): 41 | all_nums = permutations(l) 42 | for n in all_nums: 43 | if is_prime(n) and largest < n: 44 | largest = n 45 | found = True 46 | 47 | if found: 48 | break 49 | 50 | print(largest) 51 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro042_triangular_number.py: -------------------------------------------------------------------------------- 1 | MAX_DELTA = 1000 2 | CACHE = [1] 3 | delta = 2 4 | 5 | while delta <= MAX_DELTA: 6 | CACHE.append(CACHE[-1] + delta) 7 | delta += 1 8 | 9 | 10 | def word_to_scala(word): 11 | BASE = ord('A') - 1 12 | return sum(ord(c) for c in word) - (BASE * len(word)) 13 | 14 | 15 | def is_triangular_number(n): 16 | global CACHE 17 | 18 | def search(lo, hi): 19 | if lo == hi: 20 | return n == CACHE[lo] 21 | 22 | mid = (lo + hi) // 2 23 | if n <= CACHE[mid]: 24 | return search(lo, mid) 25 | else: 26 | return search(mid+1, hi) 27 | 28 | return search(0, len(CACHE)) 29 | 30 | 31 | if __name__ == '__main__': 32 | words_text = open('./data042').read() 33 | words = words_text.replace(r'"', '').replace('\n', '').split(',') 34 | ans = 0 35 | 36 | for word in words: 37 | scala = word_to_scala(word) 38 | ans += is_triangular_number(scala) 39 | 40 | print(ans) 41 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro043_sum_pandigital.py: -------------------------------------------------------------------------------- 1 | def get_digit(n, start, length): 2 | n = str(n) 3 | return n[start-1:start-1+length] 4 | 5 | 6 | def sum_pandigial(): 7 | LENGTH = 3 8 | used = [False] * 10 9 | starts = [2, 3, 4, 5, 6, 7, 8] 10 | dividers = [2, 3, 5, 7, 11, 13, 17] 11 | pandigitals = [] 12 | ans = [] 13 | 14 | def generate_pandigitals(tmp, used, left): 15 | nonlocal pandigitals 16 | if not left: 17 | pandigitals.append(tmp) 18 | return 19 | 20 | for n in range(10): 21 | if not used[n]: 22 | used[n] = True 23 | generate_pandigitals(tmp + str(n), used, left-1) 24 | used[n] = False 25 | 26 | generate_pandigitals('', used, 10) 27 | 28 | for pan in pandigitals: 29 | if all(int(get_digit(pan, start, LENGTH)) % divider == 0 for start, divider in zip(starts, 30 | dividers)): 31 | ans.append(int(pan)) 32 | 33 | return ans 34 | 35 | 36 | if __name__ == '__main__': 37 | ans = sum_pandigial() 38 | print(ans) 39 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro044_pentagoanl_number.py: -------------------------------------------------------------------------------- 1 | def create_pentagonal_list(size): 2 | ret = [] 3 | for n in range(1, size+1): 4 | ret.append(n * (3*n - 1) // 2) 5 | 6 | return ret 7 | 8 | 9 | if __name__ == '__main__': 10 | pentas = create_pentagonal_list(10000) 11 | penta_set = set(pentas) 12 | ans = float('inf') 13 | 14 | for i in range(len(pentas)): 15 | n1 = pentas[i] 16 | for j in range(i+1, len(pentas)): 17 | n2 = pentas[j] 18 | if (n1 + n2) in penta_set and (n2 - n1) in penta_set: 19 | ans = min(ans, n2 - n1) 20 | 21 | print(ans) 22 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro045_hexpentatrigonal_number.py: -------------------------------------------------------------------------------- 1 | def hex_generator(start=1): 2 | n = start 3 | while True: 4 | yield n * (n + 1) // 2 5 | n += 1 6 | 7 | 8 | def penta_generator(start=1): 9 | n = start 10 | while True: 11 | yield n * (3*n - 1) // 2 12 | n += 1 13 | 14 | 15 | def trigonal_generator(start=1): 16 | n = start 17 | while True: 18 | yield n * (2*n - 1) 19 | n += 1 20 | 21 | 22 | if __name__ == '__main__': 23 | tri_gen = trigonal_generator(285) 24 | pen_gen = penta_generator(165) 25 | hex_gen = hex_generator(144) # 143에서 1 키움 26 | 27 | t, p, h = next(tri_gen), next(pen_gen), next(hex_gen) 28 | 29 | while not (t == p == h): 30 | min_n = min(t, p, h) 31 | if min_n == h: 32 | h = next(hex_gen) 33 | elif min_n == p: 34 | p = next(pen_gen) 35 | else: 36 | t = next(tri_gen) 37 | 38 | 39 | print(t) 40 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro046_composite_conjecture.py: -------------------------------------------------------------------------------- 1 | def is_prime(n): 2 | if n == 1: 3 | return False 4 | elif n == 2: 5 | return True 6 | elif not n % 2: 7 | return False 8 | 9 | for d in range(3, int(n ** (1/2))+1, 2): 10 | if not n % d: 11 | return False 12 | 13 | return True 14 | 15 | 16 | def is_composite(n): 17 | return not is_prime(n) if n != 1 else False 18 | 19 | 20 | if __name__ == '__main__': 21 | n = 7 22 | is_ok = True 23 | 24 | while is_ok: 25 | n += 2 26 | if not is_composite(n): 27 | continue 28 | 29 | is_ok = False 30 | c = 1 31 | 32 | while n > 2 * (c ** 2): 33 | left = n - 2 * (c ** 2) 34 | if is_prime(left): 35 | is_ok = True 36 | break 37 | 38 | c += 1 39 | 40 | 41 | print(n) 42 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro047_same_count_factors_numbers.py: -------------------------------------------------------------------------------- 1 | def get_factors(n): 2 | ret = set() 3 | d = 3 4 | 5 | while not n % 2: 6 | ret.add(2) 7 | n //= 2 8 | 9 | while n != 1: 10 | while not n % d: 11 | ret.add(d) 12 | n //= d 13 | d += 2 14 | 15 | return ret 16 | 17 | 18 | if __name__ == '__main__': 19 | n = 1 20 | while True: 21 | if len(get_factors(n)) != 4: 22 | n += 1 23 | elif len(get_factors(n+1)) != 4: 24 | n += 2 25 | elif len(get_factors(n+2)) != 4: 26 | n += 3 27 | elif len(get_factors(n+3)) != 4: 28 | n += 4 29 | else: 30 | print(n) 31 | break 32 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro048_last_ten_digits.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | ans = 0 3 | for n in range(1, 1001): 4 | ans += pow(n, n, 10 ** 10) 5 | 6 | ans %= 10 ** 10 7 | 8 | print(ans) 9 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro049_anagram_arithmetical_progression.py: -------------------------------------------------------------------------------- 1 | def are_anagrams(n1, n2): 2 | return sorted(str(n1)) == sorted(str(n2)) 3 | 4 | 5 | if __name__ == '__main__': 6 | ans = [] 7 | sieve = [1] * (10000 + 1) 8 | sieve[0] = sieve[1] = 0 9 | 10 | for i in range(2, int(10000 ** (1/2))+1): 11 | if sieve[i]: 12 | for j in range(i*i, 10000+1, i): 13 | sieve[j] = 0 14 | 15 | 16 | for n in range(1000, 10000): 17 | d = 1 18 | while n + 2 * d < 10000: 19 | if sieve[n] and sieve[n + d] and sieve[n + 2 * d] \ 20 | and are_anagrams(n, n + d) and are_anagrams(n + 2 * d, n): 21 | ans.append((n, n + d, n + 2 * d)) 22 | d += 1 23 | 24 | print(ans) 25 | -------------------------------------------------------------------------------- /problems_solving/project-euler/pro050_longest_prime_sum_prime.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | SIZE = 10 ** 6 3 | sieve = [1] * (SIZE + 1) 4 | sieve[1] = sieve[0] = 0 5 | 6 | for i in range(2, int(SIZE ** (1/2))+1): 7 | if sieve[i]: 8 | for j in range(i*i, SIZE+1, i): 9 | sieve[j] = 0 10 | 11 | primes = [i for i, n in enumerate(sieve) if n == 1] 12 | prime_set = set(primes) 13 | cum_primes = [0] 14 | 15 | for n in primes: 16 | cum_primes.append(cum_primes[-1] + n) 17 | 18 | 19 | length = 0 20 | ans = None 21 | 22 | for lo in range(1, len(cum_primes)): 23 | for hi in range(lo+length, len(cum_primes)): 24 | cum_sum = cum_primes[hi] - cum_primes[lo-1] 25 | if (cum_sum in prime_set) and (hi - lo + 1) > length: 26 | length = hi - lo + 1 27 | ans = cum_sum 28 | 29 | if cum_sum > SIZE: 30 | break 31 | print(ans) 32 | -------------------------------------------------------------------------------- /search-algorithm/binary_search.py: -------------------------------------------------------------------------------- 1 | """Binary search module 2 | 3 | Start Date: 2017/12/08 4 | Last modified Date: 2018/12/11 5 | 6 | github.com/shoark7 7 | """ 8 | __version__ = '2.0.0' 9 | 10 | 11 | def binary_search(arr, v): 12 | arr.sort() 13 | def find(lo, hi): 14 | mid = (lo + hi) // 2 15 | if lo == hi: 16 | return lo if arr[lo] == v else -1 17 | elif arr[mid] < v: 18 | return find(mid+1, hi) 19 | else: 20 | return find(lo, mid) 21 | 22 | return find(0, len(arr)-1) 23 | -------------------------------------------------------------------------------- /simple_data_structure/stack.py: -------------------------------------------------------------------------------- 1 | """Simple array-based stack in Python 2 | 3 | Stack is FILO or LIFO data structure. 4 | Stack here has methods like below: 5 | 1. push 6 | 2. pop 7 | 3. is_empty 8 | 4. is_full 9 | 10 | Date: 2018/02/24 11 | """ 12 | 13 | 14 | class Stack: 15 | """Array-based stack in Python 16 | 17 | It has max_size variable that defaults to 10. 18 | You have to assign it when you initialize the stack. 19 | 20 | It has these kinds of methods: 21 | is_empty: Check if stack is empty 22 | is_full : Check if stack is full 23 | push : Push a value into a stack 24 | pop : PUll out the top element 25 | """ 26 | def __init__(self, max_size=10): 27 | self._max_size = max_size 28 | self._top = 0 29 | self.__body = [0 for _ in range(self._max_size)] 30 | 31 | def is_empty(self): 32 | """Check if stack is empty. 33 | 34 | Returns True if stack is empty. 35 | Otherwise, it returns False 36 | """ 37 | if self._top == 0: 38 | return True 39 | else: 40 | return False 41 | 42 | def is_full(self): 43 | """Check if stack is full. 44 | 45 | Returns True if stack's top equals to stack's max size. 46 | Otherwise, it returns False 47 | """ 48 | if self._top == self._max_size: 49 | return True 50 | else: 51 | return False 52 | 53 | def push(self, value): 54 | """Push a value to the tip of the stack""" 55 | if self.is_full(): 56 | raise ValueError("Stack is full") 57 | self.__body[self._top] = value 58 | self._top += 1 59 | 60 | def pop(self): 61 | """Pull out the last element in the stack""" 62 | if self.is_empty(): 63 | raise ValueError("Stack doesn't have any element") 64 | self._top -= 1 65 | value = self.__body[self._top] 66 | return value 67 | -------------------------------------------------------------------------------- /sorting/bubble_sort.py: -------------------------------------------------------------------------------- 1 | """Bubble sort in Python 2 | 3 | Date: 2018/02/08 4 | """ 5 | 6 | 7 | def bubble_sort(target, reverse=False): 8 | length = len(target) 9 | if reverse: 10 | for i in range(length-1): 11 | for j in range(length-1): 12 | if target[j] < target[j+1]: 13 | target[j], target[j+1] = target[j+1], target[j] 14 | else: 15 | for i in range(length-1): 16 | for j in range(length-1): 17 | if target[j] > target[j+1]: 18 | target[j], target[j+1] = target[j+1], target[j] 19 | return target 20 | -------------------------------------------------------------------------------- /sorting/insertion_sort.py: -------------------------------------------------------------------------------- 1 | """Insertion sort in Python 2 | 3 | 4 | Date: 2018/03/02 5 | """ 6 | 7 | 8 | def insertion_sort(arr, reverse=False): 9 | """Insertion sort in Python""" 10 | length = len(arr) 11 | 12 | if reverse: 13 | for i in range(1, length): 14 | while i >= 1: 15 | if arr[i] > arr[i-1]: 16 | arr[i], arr[i-1] = arr[i-1], arr[i] 17 | i -= 1 18 | else: 19 | break 20 | else: 21 | for i in range(1, length): 22 | while i >= 1: 23 | if arr[i] < arr[i-1]: 24 | arr[i], arr[i-1] = arr[i-1], arr[i] 25 | i -= 1 26 | else: 27 | break 28 | return arr 29 | -------------------------------------------------------------------------------- /sorting/merge_sort.py: -------------------------------------------------------------------------------- 1 | """Merge sort in Python 2 | 3 | 4 | Updated to version 2: 5 | This time, divide returns [lo, hi] which directs to start and end points of an interval. 6 | 7 | Date: 2019/04/19 8 | """ 9 | def merge_sort(arr): 10 | def divide(lo, hi): 11 | if lo == hi: 12 | return (lo, lo) 13 | 14 | mid = (lo + hi) // 2 15 | left = divide(lo, mid) 16 | right = divide(mid+1, hi) 17 | 18 | merge(left, right) 19 | return (lo, hi) 20 | 21 | 22 | def merge(left, right): 23 | ll, lh = left 24 | rl, rh = right 25 | 26 | left = ll 27 | right = rl 28 | tmp = [] 29 | 30 | while left <= lh or right <= rh: 31 | if left > lh or (right <= rh and arr[right] < arr[left]): 32 | tmp.append(arr[right]) 33 | right += 1 34 | else: 35 | tmp.append(arr[left]) 36 | left += 1 37 | 38 | arr[ll:rh+1] = tmp 39 | 40 | return arr if not arr else (divide(0, len(arr)-1) and arr) 41 | -------------------------------------------------------------------------------- /sorting/quick_sort.py: -------------------------------------------------------------------------------- 1 | """Quick sort in Python 2 | 3 | Python cache code is brilliant I guess. 4 | 5 | Date: 2019/04/20 6 | """ 7 | def quick_sort(arr): 8 | def sort(lo, hi): 9 | if lo < hi: 10 | pivot = partition(lo, hi) 11 | sort(lo, pivot) 12 | sort(pivot+1, hi) 13 | 14 | def partition(lo, hi): 15 | mid = (lo + hi) // 2 16 | pivot = arr[mid] 17 | left = lo 18 | right = hi 19 | 20 | while True: 21 | while left <= hi and arr[left] < pivot: 22 | left += 1 23 | 24 | while right >= 0 and pivot < arr[right]: 25 | right -= 1 26 | 27 | if left >= right: 28 | return right 29 | 30 | arr[left], arr[right] = arr[right], arr[left] 31 | right -= 1 32 | left += 1 33 | 34 | sort(0, len(arr)-1) 35 | return arr 36 | 37 | 38 | def quick_sort_cache(arr, reverse=True): 39 | """Quick sort using cache in Python 40 | 41 | This source is from wikipedia. 42 | It uses cache for quick sort. 43 | """ 44 | if len(arr) <= 1: 45 | return arr 46 | 47 | pivot = arr[len(arr) // 2] 48 | less, equal, more = [], [], [] 49 | 50 | for n in arr: 51 | if n < pivot: 52 | less.append(n) 53 | elif n == pivot: 54 | equal.append(n) 55 | else: 56 | more.append(n) 57 | 58 | return quick_sort_cache(less, reverse) + equal + quick_sort_cache(more, reverse) 59 | -------------------------------------------------------------------------------- /sorting/radix_sort.py: -------------------------------------------------------------------------------- 1 | """Radix sort in Python 2 | 3 | 4 | Date: 2018/02/18 5 | """ 6 | 7 | 8 | def radix_sort(target, reverse=False): 9 | """Radix sort in Python 10 | 11 | This sort uses 'queue way'. But simply uses list in Python. 12 | Also it assumes all elements in target are POSITIVE INTEGERS. 13 | """ 14 | def get_nth_digit(n, d): 15 | n %= 10 ** d 16 | return n // 10 ** (d-1) 17 | 18 | digit = 0 19 | max_value = max(target) 20 | while max_value: 21 | digit += 1 22 | max_value //= 10 23 | 24 | sort_queue = list() 25 | iter_range = range(10) if not reverse else range(9, -1, -1) 26 | 27 | for d in range(1, digit+1): 28 | for i in iter_range: 29 | for n in target: 30 | if get_nth_digit(n, d) == i: 31 | sort_queue.append(n) 32 | target[:] = sort_queue.copy() # Can you guess why assignment is like this? 33 | sort_queue.clear() 34 | return target 35 | -------------------------------------------------------------------------------- /sorting/selection_sort.py: -------------------------------------------------------------------------------- 1 | """Selection sort 2 | 3 | Date : 2018/02/05 4 | """ 5 | 6 | 7 | def selection_sort(target, reverse=False): 8 | """Selecetion sort in Python""" 9 | for i in range(len(target)): 10 | tmp = i 11 | if not reversed: 12 | for j in range(i, len(target)): 13 | if target[tmp] > target[j]: 14 | tmp = j 15 | else: 16 | for j in range(i, len(target)): 17 | if target[tmp] < target[j]: 18 | tmp = j 19 | target[tmp], target[i] = target[i], target[tmp] 20 | return target 21 | -------------------------------------------------------------------------------- /sorting/shell_sort.py: -------------------------------------------------------------------------------- 1 | """Shell sort in Python 2 | 3 | Date: 2018/02/20 4 | """ 5 | 6 | 7 | def shell_sort(arr, reverse=False): 8 | """Shell sort in Python""" 9 | gap = len(arr) // 3 + 1 10 | n = len(arr) // gap 11 | 12 | def sort_by_gap(gap, n): 13 | if not reverse: 14 | for s in range(gap): 15 | for k in range(1, n): 16 | while k > 0: 17 | if arr[s+gap*k] < arr[s+gap*(k-1)]: 18 | arr[s+gap*k], arr[s+gap*(k-1)] = arr[s+gap*(k-1)], arr[s+gap*k] 19 | k -= 1 20 | else: 21 | break 22 | else: 23 | for s in range(gap): 24 | for k in range(1, n): 25 | while k > 0: 26 | if arr[s+gap*k] > arr[s+gap*(k-1)]: 27 | arr[s+gap*k], arr[s+gap*(k-1)] = arr[s+gap*(k-1)], arr[s+gap*k] 28 | k -= 1 29 | else: 30 | break 31 | 32 | new_gap = gap // 2 33 | if new_gap <= 0: 34 | return 35 | 36 | sort_by_gap(new_gap, len(arr) // new_gap) 37 | 38 | sort_by_gap(gap, n) 39 | 40 | return arr 41 | -------------------------------------------------------------------------------- /str/trie.py: -------------------------------------------------------------------------------- 1 | # 1. 고전적인 Trie 선언. 영어 소문자만 사용한다고 가정 2 | ALPHA_LENGTH = 26 3 | 4 | def to_number(char): 5 | return ord(char) - ord('a') 6 | 7 | 8 | class TrieNode: 9 | def __init__(self): 10 | self.children = [None] * ALPHA_LENGTH 11 | self.terminal = False 12 | 13 | def insert(self, word, idx=0): 14 | if idx == len(word): 15 | self.terminal = True 16 | else: 17 | char = word[idx] 18 | char_num = to_number(char) 19 | if self.children[char_num] is None: 20 | self.children[char_num] = TrieNode() 21 | node = self.children[char_num] 22 | node.insert(word, idx+1) 23 | 24 | def find(self, word, idx=0): 25 | if idx == len(word): 26 | return self.terminal 27 | else: 28 | char = word[idx] 29 | char_num = to_number(char) 30 | if self.children[char_num] is None: 31 | return False 32 | else: 33 | node = self.children[char_num] 34 | return node.find(word, idx+1) 35 | 36 | 37 | # 2. 나만의 방식. children을 "char: node" 형태로 표현 38 | class TrieNode: 39 | def __init__(self, is_root=False): 40 | self.children = {} 41 | self.terminal = False 42 | self.is_root = is_root 43 | 44 | def insert(self, word, idx=0): 45 | if len(word) == idx: 46 | self.terminal = True 47 | else: 48 | char = word[idx] 49 | if char not in self.children: 50 | self.children[char] = TrieNode() 51 | 52 | node = self.children[char] 53 | node.insert(word, idx+1) 54 | 55 | 56 | def find(self, word, idx=0): 57 | if idx == len(word): 58 | return self.terminal 59 | else: 60 | char = word[idx] 61 | if char not in self.children: 62 | return False 63 | else: 64 | node = self.children[char] 65 | return node.find(word, idx+1) 66 | -------------------------------------------------------------------------------- /tree/binary_tree.py: -------------------------------------------------------------------------------- 1 | """Binary Tree in Python 2 | 3 | 4 | """ 5 | 6 | 7 | class Node: 8 | def __init__(self, data, parent=None, left=None, right=None): 9 | self.data = data 10 | self.parent = parent 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class BinaryTree: 16 | def __init__(self, data): 17 | self.root = Node(data) 18 | 19 | def append(node): 20 | def _append(data): 21 | if not self.root.left and not self.root.right: 22 | node.left = Node(data, parent=node) 23 | elif self.root.left and not self.root.right: 24 | node.right = Node(data, parent=node) 25 | else: 26 | _append(node.left) 27 | _append(data) 28 | --------------------------------------------------------------------------------