InternBootcamp/internbootcamp/bootcamp/ckuroandwalkingroute/ckuroandwalkingroute.py
2025-05-23 15:27:15 +08:00

302 lines
9.1 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""#
### 谜题描述
Kuro is living in a country called Uberland, consisting of n towns, numbered from 1 to n, and n - 1 bidirectional roads connecting these towns. It is possible to reach each town from any other. Each road connects two towns a and b. Kuro loves walking and he is planning to take a walking marathon, in which he will choose a pair of towns (u, v) (u ≠ v) and walk from u using the shortest path to v (note that (u, v) is considered to be different from (v, u)).
Oddly, there are 2 special towns in Uberland named Flowrisa (denoted with the index x) and Beetopia (denoted with the index y). Flowrisa is a town where there are many strong-scent flowers, and Beetopia is another town where many bees live. In particular, Kuro will avoid any pair of towns (u, v) if on the path from u to v, he reaches Beetopia after he reached Flowrisa, since the bees will be attracted with the flower smell on Kuros body and sting him.
Kuro wants to know how many pair of city (u, v) he can take as his route. Since hes not really bright, he asked you to help him with this problem.
Input
The first line contains three integers n, x and y (1 ≤ n ≤ 3 ⋅ 10^5, 1 ≤ x, y ≤ n, x ≠ y) - the number of towns, index of the town Flowrisa and index of the town Beetopia, respectively.
n - 1 lines follow, each line contains two integers a and b (1 ≤ a, b ≤ n, a ≠ b), describes a road connecting two towns a and b.
It is guaranteed that from each town, we can reach every other town in the city using the given roads. That is, the given map of towns and roads is a tree.
Output
A single integer resembles the number of pair of towns (u, v) that Kuro can use as his walking route.
Examples
Input
3 1 3
1 2
2 3
Output
5
Input
3 1 3
1 2
1 3
Output
4
Note
On the first example, Kuro can choose these pairs:
* (1, 2): his route would be 1 → 2,
* (2, 3): his route would be 2 → 3,
* (3, 2): his route would be 3 → 2,
* (2, 1): his route would be 2 → 1,
* (3, 1): his route would be 3 → 2 → 1.
Kuro can't choose pair (1, 3) since his walking route would be 1 → 2 → 3, in which Kuro visits town 1 (Flowrisa) and then visits town 3 (Beetopia), which is not allowed (note that pair (3, 1) is still allowed because although Kuro visited Flowrisa and Beetopia, he did not visit them in that order).
On the second example, Kuro can choose the following pairs:
* (1, 2): his route would be 1 → 2,
* (2, 1): his route would be 2 → 1,
* (3, 2): his route would be 3 → 1 → 2,
* (3, 1): his route would be 3 → 1.
Here is a reference code to solve this task. You can use this to help you genereate cases or validate the solution.
```python
from collections import deque
def shittyDfs(m, visited, start, end):
queue = deque()
queue.append(start)
under = 0
while len(queue) > 0:
cur = queue.pop()
if cur in visited:
continue
if cur == end:
return (True, 0)
visited[cur] = True
under += 1
for n in m[cur]:
queue.append(n)
return (False, under)
def shittyDfsRecursive(m, visited, start, end):
if start in visited:
return (False, 0)
if start == end:
return (True, 0)
visited[start] = True
num_under = 1
for n in m[start]:
out = shittyDfs(m, visited, n, end)
if out[0]:
return (True, 0)
num_under += out[1]
return (False, num_under)
def addToMap(m, x, y):
if x in m:
m[x].append(y)
else:
m[x] = [y]
def underExcept(m, start, end):
under = 1
for n in m[start]:
out = shittyDfs(m, {start: True}, n, end)
if out[0]:
continue
under += out[1]
return under
def foo():
n, f, b = [int(x) for x in raw_input().split(' ')]
m = {}
for i in range(n - 1):
x, y = [int(x) for x in raw_input().split(' ')]
addToMap(m, x, y)
addToMap(m, y, x)
num_f = underExcept(m, f, b)
num_b = underExcept(m, b, f)
print(n * (n - 1) - num_f * num_b)
foo()
```
请完成上述谜题的训练场环境类实现,包括所有必要的方法。
"""
from bootcamp import Basebootcamp
import random
from collections import deque, defaultdict
from bootcamp import Basebootcamp
class Ckuroandwalkingroutebootcamp(Basebootcamp):
def __init__(self, max_n=10, default_n=None, x=None, y=None):
"""
初始化训练场参数设置生成案例的最大n值、默认n值以及固定的x/y可选
"""
self.params = {
'max_n': max_n,
'default_n': default_n,
'x': x,
'y': y
}
def case_generator(self):
"""
生成符合题目要求的树结构案例包含n、x、y、边列表及正确答案
"""
n = self.params['default_n'] if self.params['default_n'] is not None else random.randint(2, self.params['max_n'])
edges = []
if n > 1:
parents = {}
# 生成随机树结构
for i in range(2, n+1):
p = random.randint(1, i-1)
parents[i] = p
edges.append((p, i))
adj = defaultdict(list)
for a, b in edges:
adj[a].append(b)
adj[b].append(a)
# 确定x和y的值确保x != y
x = self.params['x'] if self.params['x'] is not None else random.randint(1, n)
y = self.params['y'] if self.params['y'] is not None else random.choice([i for i in range(1, n+1) if i != x])
while x == y: # 确保x和y不同
y = random.randint(1, n)
# 计算正确答案
num_f = self._compute_under_except(adj, x, y)
num_b = self._compute_under_except(adj, y, x)
correct = n * (n - 1) - num_f * num_b
return {
'n': n,
'x': x,
'y': y,
'edges': edges,
'correct_answer': correct
}
def _compute_under_except(self, adj, start, end):
"""
计算underExcept值从start出发不经过通向end路径的子树大小
"""
if start == end:
return 0
path = self._find_path(adj, start, end)
if not path:
return 0
next_node = path[1] if len(path) > 1 else None
total = 1 # 包含start自己
for neighbor in adj[start]:
if neighbor == next_node:
continue
# 计算该邻接点子树的节点数
count = 0
visited = {start}
stack = [neighbor]
while stack:
node = stack.pop()
if node in visited:
continue
visited.add(node)
count += 1
for v in adj[node]:
if v not in visited:
stack.append(v)
total += count
return total
def _find_path(self, adj, start, end):
"""
使用BFS找到start到end的路径
"""
parent = {}
queue = deque([start])
parent[start] = None
while queue:
u = queue.popleft()
if u == end:
break
for v in adj[u]:
if v not in parent and v != parent.get(u):
parent[v] = u
queue.append(v)
if end not in parent:
return []
# 重建路径
path = []
current = end
while current is not None:
path.append(current)
current = parent[current]
return path[::-1]
@staticmethod
def prompt_func(question_case) -> str:
"""
将案例转换为自然语言问题描述,包含输入格式和答案格式要求
"""
n = question_case['n']
x = question_case['x']
y = question_case['y']
edges = question_case['edges']
input_lines = [f"{a} {b}" for a, b in edges]
input_str = f"{n} {x} {y}\n" + "\n".join(input_lines)
return f"""Ckuroandwalkingroute需要选择一条跑步路线该路线不能先后经过Flowrisa城镇{x}和Beetopia城镇{y}。Uberland有{n}个城镇,通过以下道路连接:
{input_str}
请计算有效的(u, v)路径对的数量u≠v其中路径不会先经过{x}再经过{y}。答案应为整数,放在[answer]标签内。例如:[answer]5[/answer]。"""
@staticmethod
def extract_output(output):
"""
从模型输出中提取最后一个[answer]标签内的整数
"""
import re
matches = re.findall(r'\[answer\]\s*(\d+)\s*\[/answer\]', output, re.IGNORECASE)
if not matches:
return None
try:
return int(matches[-1])
except:
return None
@classmethod
def _verify_correction(cls, solution, identity):
"""
验证答案是否与预计算的正確答案一致
"""
return solution == identity['correct_answer']