commit f4d7f7899cb93259584750b1b5b283a57dd1621a Author: rogerwang2008 Date: Thu Jul 23 14:22:17 2026 +0800 Initial 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 0000000..c0a3ae1 Binary files /dev/null and b/.idea/CodeEpiphany/challenges.db differ diff --git a/.idea/CodeEpiphany/luogu.xml b/.idea/CodeEpiphany/luogu.xml new file mode 100644 index 0000000..c454d6d --- /dev/null +++ b/.idea/CodeEpiphany/luogu.xml @@ -0,0 +1,10 @@ + + + + + + \ 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 = "." }