PAT甲级有一道关于真题 All Roads Lead to Rome
Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.
输入描述:
Each input file contains one test case. For each case, the first line contains 2 positive integers N (2<=N<=200), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N-1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format “City1 City2 Cost”. Here the name of a city is a string of 3 capital English letters, and the destination is always ROM which represents Rome.
输出描述:
For each test case, we are supposed to find the route with the least cost. If such a route is not unique, the one with the maximum happiness will be recommended. If such a route is still not unique, then we output the one with the maximum average happiness – it is guaranteed by the judge that such a solution exists and is unique. Hence in the first line of output, you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommended route. Then in the next line, you are supposed to print the route in the format “City1->City2->…->ROM”.
这虽然是一道典型的Dijkstra算法的题,但需要做的判断都非常复杂。这主要源于不仅仅需要判断哪条路的成本最少,还要在成本相同的情况下判断其中哪条路能获得更多的幸福值,以及平均幸福值最大的路。但这些条件仍然能够通过局部最优来达到全局最优,故而可以使用Dijkstra算法处理。(包括求解最短路径数量)
from collections import defaultdict
import heapq
= lambda x: int(x) if x.isdigit() else x
general_func
= map(
N, K, starting_city input().strip().split()
general_func,
)
= {starting_city : 0}
happiness_cities
= defaultdict(set)
adj for _ in range(N - 1):
= map(
city, happiness input().strip().split()
general_func,
)= happiness
happiness_cities[city] for _ in range(K):
= map(
src, dst, consume_happiness input().strip().split()
general_func,
)
adj[src].add((dst, consume_happiness))
adj[dst].add((src,consume_happiness))= float('inf')
INF def find_best_route(n, k, start, happiness, graph):
# 初始化图和幸福值
# 初始化 Dijkstra 相关变量
= defaultdict(lambda: INF) # 最短距离
dist = 0
dist[start] = defaultdict(int) # 从起点到每个节点的路径数
num_paths = 1
num_paths[start] = defaultdict(int) # 从起点到每个节点的最大幸福值
max_happiness = defaultdict(list) # 用于记录路径
prev
= set()
visited
# 优先队列 (距离, - 总幸福值, 已访问的节点数, 当前城市)
= [(0, 0, 1, start)]
pq
while pq:
= heapq.heappop(pq)
cur_dist, cur_happiness, city_count, cur_city if cur_city in visited:
continue # 跳过已经遍历过的节点,加快速度。
= -cur_happiness
cur_happiness
# 遍历邻居节点
for neighbor, cost in (graph[cur_city] - visited):
= cur_dist + cost
new_dist = cur_happiness + happiness[neighbor]
new_happiness
# 如果找到更短的路径
if new_dist < dist[neighbor]:
= new_dist
dist[neighbor] = new_happiness
max_happiness[neighbor] = cur_city
prev[neighbor] = num_paths[cur_city]
num_paths[neighbor] -new_happiness, city_count + 1, neighbor))
heapq.heappush(pq, (new_dist,
# 如果路径长度相同,则更新幸福值和路径计数
elif new_dist == dist[neighbor]:
+= num_paths[cur_city]
num_paths[neighbor] if new_happiness > max_happiness[neighbor]:
= new_happiness
max_happiness[neighbor] = cur_city
prev[neighbor] elif new_happiness == max_happiness[neighbor]:
# 更新平均幸福值最大路径
if (max_happiness[neighbor] / city_count) < (new_happiness / (city_count + 1)):
= cur_city
prev[neighbor]
visited.add(cur_city)
# 构建结果路径
= []
path = "ROM"
city while city:
path.append(city)= prev.get(city, None)
city
path.reverse()
# 输出结果
= dist["ROM"]
total_cost = max_happiness["ROM"]
total_happiness = total_happiness // (len(path) - 1)
avg_happiness = num_paths["ROM"]
num_routes
return f"{num_routes} {total_cost} {total_happiness} {avg_happiness}\n{'->'.join(path)}"
= find_best_route(N,K,starting_city,happiness_cities,adj)
r print(r)