往期
- 【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_0:介绍了题目和背景
- 【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_1:题目输入的格式说明,选择了邻接表来表示图
- 【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_2:介绍了邻接表,题目输出的格式说明
- 【用deepseek和chatgpt做算法竞赛】——华为算法精英实战营第十九期-Minimum Cost Trees_3:期主要写一个初代程序,能完整一些简单的例子
ChatGPT还是不行呀
0 评分规则
为了拿分咧,先来看看规则
0.1 评分等级
- 单棵树: 如果是单棵树,得 5 分。
- 满足延迟约束的单棵树: 如果树满足延迟约束,则得 10 分。
- 两棵边不相交的树:如果是两棵边不相交的树,得 20 分。
- 两棵边不相交且其中一棵满足延迟约束的树: 如果是两棵边不相交的树,并且其中一棵满足延迟约束,得40 分。
- 两棵边不相交且都满足延迟约束的树: 如果是两棵边不相交的树,并且两棵都满足延迟约束,得 100 分。
0.2 评分算法
评分算法分为三个步骤:
- 确定最高等级: 首先确定最高的等级 level,即最终提交的解满足的最大条件(如树的数量、延迟约束等)。
- 计算基础分: 计算为达成该等级而获得的无条件分数 x。
- 计算附加分: 根据一个公式来计算附加分。附加分的计算方式是:
- b o n u s = 0.25 ∗ x ∗ ( 1 − s q r t ( 1 − ( b e s t S u m / p a r t i c i p a n t S u m ) ) ) bonus = 0.25 * x * (1 - sqrt(1 - (bestSum / participantSum))) bonus=0.25∗x∗(1−sqrt(1−(bestSum/participantSum)))
- 其中 bestSum 是达成该等级的最小边成本(即最佳解的边成本之和),participantSum 是参与者提交的解的边成本之和。
0.3 解的要求
根据这些评分标准,参与者提交的解需要满足以下要求:
- 图结构必须符合树的特性:即每一对节点之间必须只有一条路径(连通性要求),没有环路(无环性要求)。
- 必须能够从根节点出发,并扩展到所有其他节点(唯一根节点的要求)。
根据这些要求让GPT给出程序,但是随着这个要求过多呀,就只能给出一个看着正确但实际有问题的成程序,如下
import sys
import heapq
from collections import defaultdict
def read_graph_from_stdin():
""" 从标准输入读取图数据并解析 """
lines = sys.stdin.read().strip().split("\n")
n = int(lines[0].strip()) # 节点数
s = int(lines[1].strip()) # 源点
k = int(lines[2].strip()) # 目标节点数
terminals = list(map(int, lines[3].strip().split())) # 目标节点列表
D = int(lines[4].strip()) # 延迟约束
m = int(lines[5].strip()) # 边数
graph = defaultdict(list)
for i in range(6, 6 + m):
a, b, c, d = map(int, lines[i].strip().split())
graph[a].append((b, c, d)) # 存储 a -> b 的边
graph[b].append((a, c, d)) # 存储 b -> a 的边(无向图)
return n, s, terminals, D, graph
def is_cyclic(graph, n, visited, node, rec_stack):
""" 判断图中是否存在环(深度优先遍历) """
visited[node] = True
rec_stack[node] = True
for neighbor, _, _ in graph[node]:
if not visited[neighbor]:
if is_cyclic(graph, n, visited, neighbor, rec_stack):
return True
elif rec_stack[neighbor]:
return True
rec_stack[node] = False
return False
def find_directed_tree(n, s, terminals, D, graph, avoid_edges=set()):
""" 使用Dijkstra算法构建满足延迟约束的有向树,并尽量避免使用 avoid_edges """
pq = [(0, s, -1)] # (delay, node, parent)
min_delay = {node: float('inf') for node in range(n)}
min_delay[s] = 0
tree_edges = []
parent_map = {}
while pq:
delay, node, parent = heapq.heappop(pq)
if parent != -1 and (parent, node) not in avoid_edges:
tree_edges.append((parent, node))
for neighbor, cost, edge_delay in sorted(graph[node], key=lambda x: x[2]): # 按延迟排序
if (node, neighbor) in avoid_edges:
continue # 避免使用第一棵树中的边
new_delay = delay + edge_delay
if new_delay <= D and new_delay < min_delay[neighbor]:
min_delay[neighbor] = new_delay
heapq.heappush(pq, (new_delay, neighbor, node))
parent_map[neighbor] = node
# 判断是否能够连接所有终端节点
if not all(t in parent_map for t in terminals):
return None # 不能形成有效的树
# 检查图是否包含环
visited = [False] * n
rec_stack = [False] * n
for node in range(n):
if not visited[node]:
if is_cyclic(graph, n, visited, node, rec_stack):
return None # 如果存在环,返回无效树
return tree_edges
def process_and_output():
graph_data = read_graph_from_stdin()
if not graph_data:
return
n, s, terminals, D, graph = graph_data
# 找到第一棵树
tree1_edges = find_directed_tree(n, s, terminals, D, graph)
if not tree1_edges:
print("无法找到符合要求的树")
return
used_edges = set(tree1_edges)
# 尝试找到第二棵树(避免使用第一棵树的边)
tree2_edges = find_directed_tree(n, s, terminals, D, graph, avoid_edges=used_edges)
# 允许部分重用第一棵树的边
if not tree2_edges:
tree2_edges = find_directed_tree(n, s, terminals, D, graph, avoid_edges=set())
if not tree2_edges:
return
print(2) # 找到 2 棵树
# 第一棵树
print(len(tree1_edges))
for a, b in tree1_edges:
print(a, b)
# 第二棵树
print(len(tree2_edges))
for a, b in tree2_edges:
print(a, b)
if __name__ == "__main__":
process_and_output()