From f4d7f7899cb93259584750b1b5b283a57dd1621a Mon Sep 17 00:00:00 2001 From: rogerwang2008 Date: Thu, 23 Jul 2026 14:22:17 +0800 Subject: [PATCH] Initial --- .gitignore | 1 + .idea/.gitignore | 10 ++ .idea/CodeEpiphany/challenges.db | Bin 0 -> 151552 bytes .idea/CodeEpiphany/luogu.xml | 10 ++ .idea/MarsCodeWorkspaceAppSettings.xml | 7 + .idea/codeStyles/Project.xml | 5 + .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/exercises@1.iml | 10 ++ .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 6 + .idea/modules.xml | 9 ++ .idea/pyProjectModel.xml | 7 + .idea/vcs.xml | 6 + luogu_P1379_ida_star.py | 134 ++++++++++++++++++ luogu_P2901_a_star.py | 124 ++++++++++++++++ luogu_ez_P16681_dp.py | 38 +++++ luogu_ez_P2902.py | 16 +++ pyproject.toml | 5 + uv.lock | 8 ++ 19 files changed, 407 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/CodeEpiphany/challenges.db create mode 100644 .idea/CodeEpiphany/luogu.xml create mode 100644 .idea/MarsCodeWorkspaceAppSettings.xml create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/exercises@1.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/pyProjectModel.xml create mode 100644 .idea/vcs.xml create mode 100644 luogu_P1379_ida_star.py create mode 100644 luogu_P2901_a_star.py create mode 100644 luogu_ez_P16681_dp.py create mode 100644 luogu_ez_P2902.py create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d06e7a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.venvs diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..f6906f2 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 已忽略包含查询文件的默认文件夹 +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/CodeEpiphany/challenges.db b/.idea/CodeEpiphany/challenges.db new file mode 100644 index 0000000000000000000000000000000000000000..c0a3ae19f4c9a383f2d1196e5ab26637170efe5c GIT binary patch literal 151552 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 + + + + + \ No newline at end of file diff --git a/.idea/MarsCodeWorkspaceAppSettings.xml b/.idea/MarsCodeWorkspaceAppSettings.xml new file mode 100644 index 0000000..b26fdc6 --- /dev/null +++ b/.idea/MarsCodeWorkspaceAppSettings.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..fe83ec9 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..e402e4d --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/exercises@1.iml b/.idea/exercises@1.iml new file mode 100644 index 0000000..964dabf --- /dev/null +++ b/.idea/exercises@1.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..aa8bfc5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..32d0c6e --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/pyProjectModel.xml b/.idea/pyProjectModel.xml new file mode 100644 index 0000000..9963416 --- /dev/null +++ b/.idea/pyProjectModel.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/luogu_P1379_ida_star.py b/luogu_P1379_ida_star.py new file mode 100644 index 0000000..30472a5 --- /dev/null +++ b/luogu_P1379_ida_star.py @@ -0,0 +1,134 @@ +import sys +from typing import Iterable, Iterator, TYPE_CHECKING + + +class State(int): + def get_digit(self, idx): # 0 开始 + return self // (10 ** idx) % 10 + + def with_digit(self, idx: int, val: int) -> "State": + return State(self + (val - self.get_digit(idx)) * 10 ** idx) + + def get_coord_digit(self, row: int, col: int): + idx = 3 * (3 - row) - (col + 1) + return self.get_digit(idx) + + def with_coord_digit(self, row: int, col: int, val: int) -> "State": + idx = 3 * (3 - row) - (col + 1) + return self.with_digit(idx, val) + + def get_number_coord(self, n: int = 0) -> tuple[int, int]: + for r in range(3): + for c in range(3): + if self.get_coord_digit(r, c) == n: + return r, c + raise ValueError(f"No {n} in state {self}") + + def get_possible_steps(self) -> Iterable["State"]: + x0, y0 = self.get_number_coord() + if x0 > 0: + yield self.with_coord_digit(x0, y0, self.get_coord_digit(x0 - 1, y0)) \ + .with_coord_digit(x0 - 1, y0, 0) + if y0 > 0: + yield self.with_coord_digit(x0, y0, self.get_coord_digit(x0, y0 - 1)) \ + .with_coord_digit(x0, y0 - 1, 0) + if x0 < 2: + yield self.with_coord_digit(x0, y0, self.get_coord_digit(x0 + 1, y0)) \ + .with_coord_digit(x0 + 1, y0, 0) + if y0 < 2: + yield self.with_coord_digit(x0, y0, self.get_coord_digit(x0, y0 + 1)) \ + .with_coord_digit(x0, y0 + 1, 0) + + def compare_with(self, other_state: "State") -> int: + # return 0 + # return 9 - sum(self.get_digit(idx) == other_state.get_digit(idx) for idx in range(9)) + # return max(0, 8 - sum(self.get_digit(idx) == other_state.get_digit(idx) for idx in range(9))) + d1 = sum(self.get_digit(idx) != other_state.get_digit(idx) for idx in range(9)) + if self.get_number_coord() != other_state.get_number_coord(): + d1 -= 1 + d2 = self.manhattan_distance(other_state) + if d1 > d2: print("?????????", self, other_state, d1, d2) + return d1 + + def manhattan_distance(self, other_state: "State") -> int: + number_coords = {} + other_number_coords = {} + for r in range(3): + for c in range(3): + number_coords[self.get_coord_digit(r, c)] = (r, c) + other_number_coords[other_state.get_coord_digit(r, c)] = (r, c) + + # del number_coords[0] + # del other_number_coords[0] + return sum( + abs(number_coords[i][0] - other_number_coords[i][0]) + abs(number_coords[i][1] - other_number_coords[i][1]) + for i in range(1, 9)) + + +class StateNode: + def __init__(self, + state: State | int | str, cost: int, + heuristic_cost: int, + previous_state: State | None = None): + self.state = State(state) + self.cost = cost # g + self.heuristic_cost = heuristic_cost # h + self.previous_state = previous_state + self.running_iterator: Iterator[State] | None = None + + @property + def evaluated_cost(self): + return self.heuristic_cost + self.cost + + def __lt__(self, other): + return self.evaluated_cost < other.evaluated_cost + + def __repr__(self): + return f"{self.state} (g={self.cost}, h={self.heuristic_cost})" + + +def dfs_solve(original_state: State, final_state: State, max_cost: int = 2) -> int | bool: + open_list: list[StateNode] = [StateNode(original_state, 0, original_state.compare_with(final_state))] + next_max_cost: int | float = float("inf") + while open_list: + current_node = open_list[-1] + print(open_list, file=sys.stderr) + if current_node.state == final_state: + return True + + if current_node.running_iterator is None: + current_node.running_iterator = iter(current_node.state.get_possible_steps()) + continue + + try: + new_state = next(current_node.running_iterator) + if new_state == current_node.previous_state: + continue + new_node = StateNode(new_state, current_node.cost + 1, new_state.compare_with(final_state), + current_node.state) + if new_node.evaluated_cost > max_cost: + next_max_cost = min(new_node.evaluated_cost, next_max_cost) + continue + open_list.append(new_node) + except StopIteration: + open_list.pop() + if TYPE_CHECKING: + return int(next_max_cost) + else: + return next_max_cost + + +def ida_star_solve(original_state: State, final_state: State) -> int: + max_cost = original_state.compare_with(final_state) + while True: + print(max_cost, "!!!!!!", file=sys.stderr) + result = dfs_solve(original_state, final_state, max_cost) + if result is True: + return max_cost + max_cost = result + + +if __name__ == '__main__': + original_state = State(input()) + final_state = State(123804765) + print(ida_star_solve(original_state, final_state)) diff --git a/luogu_P2901_a_star.py b/luogu_P2901_a_star.py new file mode 100644 index 0000000..39154ac --- /dev/null +++ b/luogu_P2901_a_star.py @@ -0,0 +1,124 @@ +import heapq +import sys + +INT_INF = 0x7fffffff + + +class GraphMatrix: + def __init__(self, size: int): + self.vertices = size + self.matrix = [[[] for _ in range(size)] for _ in range(size)] + + def add_edge(self, start: int, end: int, weight: int = 1): + self.matrix[start][end].append(weight) + + def get_edge(self, start: int, end: int, invert: bool = False) -> list[int]: + if invert: + return self.matrix[end][start] + else: + return self.matrix[start][end] + + def get_edge_min(self, start: int, end: int, invert: bool = False) -> int: + return min(self.get_edge(start, end, invert)) + + def get_adjacent_vertices(self, vertex: int, invert: bool = False) -> list[int]: + return [i for i in range(self.vertices) if self.get_edge(vertex, i, invert)] + + def __repr__(self): + return "\n".join([" | ".join(map(str, row)) for row in self.matrix]) + + +class VertexNode: + def __init__(self, vertex: int, cost: int, heuristic_cost: int = 0): + self.vertex = vertex + self.cost = cost + self.heuristic_cost = heuristic_cost + + @property + def evaluated_cost(self): + return self.heuristic_cost + self.cost + + def __lt__(self, other): + return self.evaluated_cost < other.evaluated_cost + + def __repr__(self): + return f"#{self.vertex}(g={self.cost},h={self.heuristic_cost})" + + +def dijkstra_init(graph: GraphMatrix, end: int) -> dict[int, int]: + open_list: list[VertexNode] = [] + heuristic_map: dict[int, int] = {} + visited: set[int] = set() + + heuristic_map[end] = 0 + heapq.heappush(open_list, VertexNode(end, 0)) + while open_list: + current_node = heapq.heappop(open_list) + if current_node.vertex in visited: + continue + visited.add(current_node.vertex) + + for next_vertex in graph.get_adjacent_vertices(current_node.vertex, True): + if next_vertex in visited: + continue + new_cost = current_node.cost + graph.get_edge_min(current_node.vertex, next_vertex, True) + # 如果新路径更短,或者该节点第一次被访问 + if new_cost < heuristic_map.get(next_vertex, INT_INF): + heuristic_map[next_vertex] = new_cost + heapq.heappush(open_list, VertexNode(next_vertex, new_cost)) + + return heuristic_map + +def a_star_solve(graph: GraphMatrix, + start: int, end: int, + count: int, + heuristic_map: dict[int, int]) -> list[int]: + open_list: list[VertexNode] = [] + # 此处不是「visited_record」!我们要记录所有访问,只是不需要展开过多。 + # 因此也不需要「更新 g 值,因为我们记录了一切 g 的节点! + # 逻辑是:1. 每条最短路径上的每个节点一定是被 expand 过的;2. 可采用的 h 可保证先找更短路 + expanded_record: dict[int, int] = {} + # node_record: dict[int, VertexNode] = {} + original_node = VertexNode(start, 0, heuristic_map.get(start, INT_INF)) + heapq.heappush(open_list, original_node) + # node_record[start] = original_node + result_list: list[int] = [] + + while open_list: + # print(open_list, file=sys.stderr) + current_node = heapq.heappop(open_list) + expanded_record[current_node.vertex] = expanded_record.get(current_node.vertex, 0) + 1 + # print(current_node, open_list, file=sys.stderr) + if current_node.vertex == end: + result_list.append(current_node.cost) + if len(result_list) >= count: + return result_list + + if expanded_record.get(current_node.vertex, 0) > count: + continue # 不扩展,剪枝 + + for next_vertex in graph.get_adjacent_vertices(current_node.vertex): + for edge_weight in graph.get_edge(current_node.vertex, next_vertex): + next_node = VertexNode( + next_vertex, + current_node.cost + edge_weight, + heuristic_map.get(next_vertex, INT_INF) + ) + heapq.heappush(open_list, next_node) + + return result_list + + +if __name__ == '__main__': + vertices_count, edge_count, result_count = map(int, input().split()) + graph = GraphMatrix(vertices_count + 1) + for _ in range(edge_count): + start, end, weight = map(int, input().split()) + graph.add_edge(start, end, weight) + # print(graph, file=sys.stderr) + heuristic_map = dijkstra_init(graph, 1) + print(heuristic_map, file=sys.stderr) + result_list = a_star_solve(graph, vertices_count, 1, result_count, heuristic_map) + # print(result_list, file=sys.stderr) + result_list += [-1] * (result_count - len(result_list)) + print(*result_list, sep="\n") diff --git a/luogu_ez_P16681_dp.py b/luogu_ez_P16681_dp.py new file mode 100644 index 0000000..ca76647 --- /dev/null +++ b/luogu_ez_P16681_dp.py @@ -0,0 +1,38 @@ +import itertools +import sys +from typing import Literal + +ROW_COUNT = 341_799 +MOD = 998_244_353 + +PatternCharType = Literal[0, 1] + + +def get_pattern_multiplier(pattern: tuple[PatternCharType, PatternCharType, PatternCharType]) -> int: + match pattern: + case (0, 0, 0) | (0, 0, 1) | (1, 0, 0) | (0, 1, 0) | (1, 0, 1): return 21 * 21 + case (0, 1, 1) | (1, 1, 0): return 21 * 26 + case (1, 1, 1): return 26 * 26 + case _: raise ValueError(f"Unknown pattern: {pattern}") + + +dp: dict[PatternCharType, list[tuple[int, int]]] = {0: [(-1, -1), (5, 0)], 1: [(-1, -1), (0, 21)]} + +for _ in range(ROW_COUNT - 1): + for c in 0, 1: + dp[c].append((dp[c][-1][1] * 5 % MOD, (dp[c][-1][0] + dp[c][-1][1]) * 21 % MOD)) + +answer = 0 + +for pattern1 in itertools.product([0, 1], repeat=3): + for pattern2 in itertools.product([0, 1], repeat=3): + # noinspection PyTypeChecker + answer += dp[pattern1[0]][ROW_COUNT][pattern2[0]] \ + * dp[pattern1[1]][ROW_COUNT][pattern2[1]] \ + * dp[pattern1[2]][ROW_COUNT][pattern2[2]] \ + * get_pattern_multiplier(pattern1) \ + * get_pattern_multiplier(pattern2) \ + % MOD + +print(dp[0][:100], dp[1][:100], file=sys.stderr, sep="\n") +print(answer % MOD) diff --git a/luogu_ez_P2902.py b/luogu_ez_P2902.py new file mode 100644 index 0000000..0a520d8 --- /dev/null +++ b/luogu_ez_P2902.py @@ -0,0 +1,16 @@ +import sys + +if __name__ == '__main__': + perl_amount, color_kind_amount = map(int, input().split()) + color_counts: list[tuple[int, int]] = [] + for i in range(color_kind_amount): + color_counts.append((i, int(input()))) + + color_counts.sort(key=lambda x: x[1]) + + colors: list[int] = [] + for i, color_count in color_counts: + colors += [i + 1] * color_count + print(colors, file=sys.stderr) + for i in range(perl_amount // 2): + print(colors[i], colors[i + perl_amount // 2]) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0a98a6c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,5 @@ +[project] +name = "exercises" +version = "0.1.0" +requires-python = ">=3.11" +dependencies = [] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..355ead1 --- /dev/null +++ b/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "exercises" +version = "0.1.0" +source = { virtual = "." }