From 140b24dbb5ab8e1230ecb86f62ad7f173e6e7a8e Mon Sep 17 00:00:00 2001 From: Aaro Koivukangas Date: Wed, 15 Apr 2026 10:39:02 +0300 Subject: [PATCH] did things --- viikko14/bellman-ford.py | 43 +++++++++++++++++++ viikko14/bestroute.py | 56 +++++++++++++++++++++++++ viikko14/dijkstra.py | 53 +++++++++++++++++++++++ viikko14/listjump.py | 62 +++++++++++++++++++++++++++ viikko14/trainprices.py | 90 ++++++++++++++++++++++++++++++++++++++++ viikko15/components.py | 46 ++++++++++++++++++++ viikko15/maxset.py | 57 +++++++++++++++++++++++++ viikko15/newroads.py | 62 +++++++++++++++++++++++++++ viikko15/smallest.py | 60 +++++++++++++++++++++++++++ 9 files changed, 529 insertions(+) create mode 100644 viikko14/bellman-ford.py create mode 100644 viikko14/bestroute.py create mode 100644 viikko14/dijkstra.py create mode 100644 viikko14/listjump.py create mode 100644 viikko14/trainprices.py create mode 100644 viikko15/components.py create mode 100644 viikko15/maxset.py create mode 100644 viikko15/newroads.py create mode 100644 viikko15/smallest.py diff --git a/viikko14/bellman-ford.py b/viikko14/bellman-ford.py new file mode 100644 index 0000000..6fa7b86 --- /dev/null +++ b/viikko14/bellman-ford.py @@ -0,0 +1,43 @@ +import time +import random + + +class BellmanFord: + def __init__(self, nodes): + self.nodes = nodes + self.edges = [] + + def add_edge(self, node_a, node_b, weight): + self.edges.append((node_a, node_b, weight)) + + def find_distances(self, start_node): + distances = {} + for node in self.nodes: + distances[node] = float("inf") + distances[start_node] = 0 + + num_rounds = len(self.nodes) - 1 + for _ in range(num_rounds): + for edge in self.edges: + node_a, node_b, weight = edge + new_distance = distances[node_a] + weight + if new_distance < distances[node_b]: + distances[node_b] = new_distance + + return distances + + +if __name__ == "__main__": + start = time.time() + ls = [x for x in range(1, 5000 + 1)] + random.shuffle(ls) + bf = BellmanFord(ls) + for i in range(1, 5000 + 1): + for j in range(1, i): + if i - j < 10: + bf.add_edge(j, i, random.randint(1, 1000)) + + distances = bf.find_distances(1) + end = time.time() + + print(f"Time: {end - start:.2f}s") diff --git a/viikko14/bestroute.py b/viikko14/bestroute.py new file mode 100644 index 0000000..32035ab --- /dev/null +++ b/viikko14/bestroute.py @@ -0,0 +1,56 @@ +import math +import heapq +class BestRoute: + def __init__(self, nodes: int): + self.nodes = [x for x in range(1, nodes+1)] + self.graph = {node: [] for node in self.nodes} + + def add_road(self, node_a, node_b, weight): + self.graph[node_a].append((node_b, weight)) + self.graph[node_b].append((node_a, weight)) + + def find_distances(self, start_node): + distances = {} + for node in self.nodes: + distances[node] = float("inf") + distances[start_node] = 0 + + queue = [] + heapq.heappush(queue, (0, start_node)) + + visited = set() + while queue: + node_a = heapq.heappop(queue)[1] + if node_a in visited: + continue + visited.add(node_a) + + for node_b, weight in self.graph[node_a]: + new_distance = distances[node_a] + weight + if new_distance < distances[node_b]: + distances[node_b] = new_distance + new_pair = (new_distance, node_b) + heapq.heappush(queue, new_pair) + + return distances + + + def find_route(self, start_n, end_n): + distances = self.find_distances(start_n) + # print(distances, distances[end_n]) + if distances[end_n] == math.inf: + return -1 + return distances[end_n] + + +if __name__ == "__main__": + routes = BestRoute(3) + + routes.add_road(1, 2, 2) + print(routes.find_route(1, 3)) # -1 + + routes.add_road(3, 1, 5) + print(routes.find_route(1, 3)) # 5 + + routes.add_road(2, 3, 1) + print(routes.find_route(1, 3)) # 3 diff --git a/viikko14/dijkstra.py b/viikko14/dijkstra.py new file mode 100644 index 0000000..4efd3ae --- /dev/null +++ b/viikko14/dijkstra.py @@ -0,0 +1,53 @@ +import time +import random +import heapq + + +class Dijkstra: + def __init__(self, nodes): + self.nodes = nodes + self.graph = {node: [] for node in nodes} + + def add_edge(self, node_a, node_b, weight): + self.graph[node_a].append((node_b, weight)) + + def find_distances(self, start_node): + distances = {} + for node in self.nodes: + distances[node] = float("inf") + distances[start_node] = 0 + + queue = [] + heapq.heappush(queue, (0, start_node)) + + visited = set() + while queue: + node_a = heapq.heappop(queue)[1] + if node_a in visited: + continue + visited.add(node_a) + + for node_b, weight in self.graph[node_a]: + new_distance = distances[node_a] + weight + if new_distance < distances[node_b]: + distances[node_b] = new_distance + new_pair = (new_distance, node_b) + heapq.heappush(queue, new_pair) + + return distances + + +if __name__ == "__main__": + start = time.time() + ls = [x for x in range(1, 5000 + 1)] + random.shuffle(ls) + d = Dijkstra(ls) + for i in range(1, 5000 + 1): + for j in range(1, i): + if i - j < 10: + d.add_edge(j, i, random.randint(1, 1000)) + + distances = d.find_distances(1) + end = time.time() + + print(f"Time: {end - start:.2f}s") diff --git a/viikko14/listjump.py b/viikko14/listjump.py new file mode 100644 index 0000000..68281ec --- /dev/null +++ b/viikko14/listjump.py @@ -0,0 +1,62 @@ +import math +import heapq + +class Dijkstra: + def __init__(self, nodes): + self.nodes = nodes + self.graph = {node: [] for node in range(len(nodes))} + + def add_edge(self, node_a, node_b, weight): + self.graph[node_a].append((node_b, weight)) + + def find_distances(self, start_node): + distances = {} + for i in range(len(self.nodes)): + distances[i] = float("inf") + distances[start_node] = 0 + + queue = [] + heapq.heappush(queue, (0, start_node)) + + visited = set() + while queue: + node_a = heapq.heappop(queue)[1] + if node_a in visited: + continue + visited.add(node_a) + + for node_b, weight in self.graph[node_a]: + new_distance = distances[node_a] + weight + if new_distance < distances[node_b]: + distances[node_b] = new_distance + new_pair = (new_distance, node_b) + heapq.heappush(queue, new_pair) + + return distances + +def find_steps(numbers): + d = Dijkstra(numbers) + for i in range(len(numbers)): + # left + if i-numbers[i] >= 0: + d.add_edge(i, i - numbers[i], numbers[i]) + # right + if i+numbers[i] < len(numbers): + d.add_edge(i, i+numbers[i], numbers[i]) + + distances = d.find_distances(0) + # print(distances, distances[len(numbers)-1]) + if distances[len(numbers)-1] == math.inf: + return -1 + return distances[len(numbers)-1] + +if __name__ == "__main__": + print(find_steps([1, 1, 1, 1])) # 3 + print(find_steps([3, 2, 1])) # -1 + print(find_steps([3, 5, 2, 2, 2, 3, 5])) # 10 + print(find_steps([7, 5, 3, 1, 4, 2, 4, 6, 1])) # 32 + + numbers = [] + for i in range(10**5): + numbers.append(1337 * i % 100 + 1) + print(find_steps(numbers)) # 100055 diff --git a/viikko14/trainprices.py b/viikko14/trainprices.py new file mode 100644 index 0000000..d2c337c --- /dev/null +++ b/viikko14/trainprices.py @@ -0,0 +1,90 @@ +import math +class TrainPrices: + def __init__(self): + self.nodes = [] + self.graph = {} + for a in self.nodes: + for b in self.nodes: + distance = 0 if a == b else float("inf") + self.graph[(a, b)] = distance + + def add_city(self, name): + self.nodes.append(name) + self.nodes.sort() + for a in self.nodes: + for b in self.nodes: + distance = 0 if a == b else float("inf") + self.graph[(a, b)] = distance + + def add_train(self, a, b, w): + self.graph[(a, b)] = min(self.graph[(a, b)], w) + self.graph[(b, a)] = min(self.graph[(a, b)], w) + + def find_prices(self): + distances = self.graph.copy() + + for k in self.nodes: + for a in self.nodes: + for b in self.nodes: + distance = min( + distances[(a, b)], distances[(a, k)] + distances[(k, b)] + ) + distances[(a, b)] = distance + + + result = [] + result.append([None] + [x for x in self.nodes]) + for x in self.nodes: + row = [x] + for y in self.nodes: + row.append(-1 if distances[(x,y)] == math.inf else distances[(x,y)]) + result.append(row) + + # print(distances) + # for x in result: + # print(x) + return result + + +class TrainPrices2: + def __init__(self): + pass + + def add_city(self, name): + pass + + def add_train(self, city1, city2, price): + pass + + def find_prices(self): + pass + + +if __name__ == "__main__": + prices = TrainPrices() + + prices.add_city("Helsinki") + prices.add_city("Turku") + prices.add_city("Tampere") + prices.add_city("Oulu") + + prices.add_train("Helsinki", "Tampere", 20) + prices.add_train("Helsinki", "Turku", 10) + prices.add_train("Tampere", "Turku", 50) + + print(prices.find_prices()) + print() + + + prices = TrainPrices() + prices.add_city("Helsinki") + prices.add_city("Oulu") + prices.add_train("Helsinki", "Oulu", 14) + print(prices.find_prices()) + + # metodin haluttu tulos: + # [[None, 'Helsinki', 'Oulu', 'Tampere', 'Turku'], + # ['Helsinki', 0, -1, 20, 10], + # ['Oulu', -1, 0, -1, -1], + # ['Tampere', 20, -1, 0, 30], + # ['Turku', 10, -1, 30, 0]] diff --git a/viikko15/components.py b/viikko15/components.py new file mode 100644 index 0000000..4f1e04b --- /dev/null +++ b/viikko15/components.py @@ -0,0 +1,46 @@ +class UnionFind: + def __init__(self, nodes): + self.link = {node: None for node in nodes} + self.size = {node: 1 for node in nodes} + + def find(self, x): + while self.link[x]: + x = self.link[x] + return x + + def union(self, a, b): + a = self.find(a) + b = self.find(b) + if a == b: + return + + if self.size[a] > self.size[b]: + a, b = b, a + self.link[a] = b + self.size[b] += self.size[a] + + +class Components: + def __init__(self, n): + self.uf = UnionFind([x for x in range(1, n + 1)]) + + def add_road(self, a, b): + self.uf.union(a, b) + + def count(self): + return list(self.uf.link.values()).count(None) + +if __name__ == "__main__": + components = Components(5) + + print(components.count()) # 5 + + components.add_road(1, 2) + components.add_road(1, 3) + print(components.count()) # 3 + + components.add_road(2, 3) + print(components.count()) # 3 + + components.add_road(4, 5) + print(components.count()) # 2 diff --git a/viikko15/maxset.py b/viikko15/maxset.py new file mode 100644 index 0000000..84aa384 --- /dev/null +++ b/viikko15/maxset.py @@ -0,0 +1,57 @@ +class UnionFind: + def __init__(self, nodes): + self.link = {node: None for node in nodes} + self.size = {node: 1 for node in nodes} + self.longest = 1 + + def find(self, x): + while self.link[x]: + x = self.link[x] + return x + + def union(self, a, b): + a = self.find(a) + b = self.find(b) + if a == b: + return + + if self.size[a] > self.size[b]: + a, b = b, a + self.link[a] = b + self.size[b] += self.size[a] + self.longest = max(self.size[b], self.longest) + + def get_max(self): + return self.longest + + +class MaxSet: + def __init__(self, n): + self.uf = UnionFind([x for x in range(1, n + 1)]) + + def merge(self, a, b): + self.uf.union(a, b) + + def get_max(self): + return self.uf.get_max() + + +if __name__ == "__main__": + max_set = MaxSet(5) + print(max_set.get_max()) # 1 + + max_set.merge(1, 2) + max_set.merge(3, 4) + max_set.merge(3, 5) + print(max_set.get_max()) # 3 + + max_set.merge(1, 5) + print(max_set.get_max()) # 5 + + max_set.merge(2, 3) + print(max_set.get_max()) # 5 + + max_set = MaxSet(10**5) + for i in range(2, 10**5 + 1): + max_set.merge(1, i) + print(max_set.get_max()) diff --git a/viikko15/newroads.py b/viikko15/newroads.py new file mode 100644 index 0000000..42222db --- /dev/null +++ b/viikko15/newroads.py @@ -0,0 +1,62 @@ +class UnionFind: + def __init__(self, nodes): + self.link = {node: None for node in nodes} + self.size = {node: 1 for node in nodes} + + def find(self, x: int): + while self.link.get(x): + x = self.link.get(x) + return x + + def union(self, a, b): + a = self.find(a) + b = self.find(b) + if a == b: + return + + if self.size[a] > self.size[b]: + a, b = b, a + self.link[a] = b + self.size[b] += self.size[a] + + +class NewRoads: + def __init__(self, nodes): + nodes = [x for x in range(1, nodes + 1)] + self.nodes = nodes + self.edges = [] + + def add_road(self, node_a, node_b, weight): + self.edges.append((node_a, node_b, weight)) + + def min_cost(self): + self.edges.sort(key=lambda x: x[2]) + + uf = UnionFind(self.nodes) + edges_count = 0 + tree_weight = 0 + + for edge in self.edges: + node_a, node_b, weight = edge + if uf.find(node_a) != uf.find(node_b): + uf.union(node_a, node_b) + edges_count += 1 + tree_weight += weight + + if edges_count != len(self.nodes) - 1: + return -1 + return tree_weight + + +if __name__ == "__main__": + new_roads = NewRoads(4) + + new_roads.add_road(1, 2, 2) + new_roads.add_road(1, 3, 5) + print(new_roads.min_cost()) # -1 + + new_roads.add_road(3, 4, 4) + print(new_roads.min_cost()) # 11 + + new_roads.add_road(2, 3, 1) + print(new_roads.min_cost()) # 7 diff --git a/viikko15/smallest.py b/viikko15/smallest.py new file mode 100644 index 0000000..6da96ab --- /dev/null +++ b/viikko15/smallest.py @@ -0,0 +1,60 @@ +class UnionFind: + def __init__(self, nodes): + self.link = {node: None for node in nodes} + self.size = {node: 1 for node in nodes} + + def find(self, x): + while self.link[x]: + x = self.link[x] + return x + + def union(self, a, b): + a = self.find(a) + b = self.find(b) + if a == b: + return + + if self.size[a] > self.size[b]: + a, b = b, a + self.link[a] = b + self.size[b] += self.size[a] + +class Kruskal: + def __init__(self, nodes): + self.nodes = nodes + self.edges = [] + + def add_edge(self, node_a, node_b, weight): + self.edges.append((node_a, node_b, weight)) + + def construct(self): + self.edges.sort(key=lambda x: -x[2]) + + uf = UnionFind(self.nodes) + edges_count = 0 + tree_weight = 0 + + for edge in self.edges: + node_a, node_b, weight = edge + if uf.find(node_a) != uf.find(node_b): + print(node_a, node_b) + uf.union(node_a, node_b) + edges_count += 1 + tree_weight += weight + + if edges_count != len(self.nodes) - 1: + return None + return tree_weight + +def main(): + nodes = [x for x in range(1,1000+1)] + k = Kruskal(nodes) + for i in nodes: + for j in range(1,i): + k.add_edge(j, i, min(i, j)) + + print(k.construct()) + + +if __name__ == "__main__": + main()