This commit is contained in:
2026-07-23 14:22:17 +08:00
commit f4d7f7899c
19 changed files with 407 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
.venvs
+10
View File
@@ -0,0 +1,10 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# 已忽略包含查询文件的默认文件夹
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
BIN
View File
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.wenjun.codeepiphany.luogu.settings">
<option name="queryCriteria">
<map>
<entry key="LuoGuChallengesView-latestUI" value="QueryParameters" />
</map>
</option>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.codeverse.userSettings.MarscodeWorkspaceAppSettingsState">
<option name="chatAppRouterInfo" value="chat-session" />
<option name="progress" value="1.0" />
</component>
</project>
+5
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="SOFT_MARGINS" value="80" />
</code_scheme>
</component>
+5
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="默认_mod" />
</state>
</component>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.system.id="pyproject.toml" type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="uv (exercises)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.14 (exercises)" />
</component>
</project>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/exercises.iml" filepath="$PROJECT_DIR$/.idea/exercises.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/exercises@1.iml" filepath="$PROJECT_DIR$/.idea/exercises@1.iml" />
</modules>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PyProjectModelSettings">
<option name="showConfigurationNotification" value="false" />
<option name="usePyprojectToml" value="true" />
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+134
View File
@@ -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))
+124
View File
@@ -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")
+38
View File
@@ -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)
+16
View File
@@ -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])
+5
View File
@@ -0,0 +1,5 @@
[project]
name = "exercises"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = []
Generated
+8
View File
@@ -0,0 +1,8 @@
version = 1
revision = 3
requires-python = ">=3.11"
[[package]]
name = "exercises"
version = "0.1.0"
source = { virtual = "." }