📜  门|门 CS 1996 |第 57 题(1)

📅  最后修改于: 2023-12-03 14:58:34.817000             🧑  作者: Mango

「门|门 CS 1996 」第 57 题

这道题目是1996年清华大学计算机系的入学考试题目,也比较经典。以下是题目描述:

有n个门连成一条直线(编号为1,2,...,n),一些门外有守卫, 而有些门里面有士兵。当一扇门有守卫时,其它门才能通过,在有多个守卫的情况下,只有一个守卫看守,这个守卫会在自己所在的门的两边各看一扇门(当然,如果门已经有守卫,则不会另外派出守卫),每扇门上的守卫都有一个级别,从小到大为1,2,...,n;这个级别也就决定了这扇门上是否有守卫和守卫的数量。如门1有1号守卫,门2有3号守卫,门3有1号和5号守卫,门4只有4号守卫,门5有1、4、5、7# 守卫(#代表空格)。当一个士兵从一扇门走到相邻的另一扇门时,所用的时间是该士兵级别的平方。现在有一个士兵要走从门1到门n(难道不是从门n到门1吗?),问你他至少是什么级别的士兵,才能保证他能在最短的时间内到达。n<=100。

思路
  • 很明显这是一道图论题目,守卫和士兵可以看作是边权为0和1的图。
  • 根据上述分析,可以构建一个有向图,从1到n有一条权值为i* i的边,只有门有守卫,将门抽象成点,则每扇门上的守卫是这个点的入度、守卫级别是入度权值。
  • 求最短路径,很明显用Dijkstra即可。
代码
import heapq

n = 100

g = [[] for _ in range(n)]
for i in range(1, n):
    for j in range(i+1, n+1):
        g[i-1].append((j-1, (j-i)**2))


def dijkstra(s: int, g: list):
    pq = []
    heapq.heappush(pq, (0, s))

    d = [float('inf')] * len(g)
    d[s] = 0

    while pq:
        v_w, v = heapq.heappop(pq)
        if d[v] < v_w:
            continue
        for next_v, next_w in g[v]:
            if d[next_v] > d[v] + next_w:
                d[next_v] = d[v] + next_w
                heapq.heappush(pq, (d[next_v], next_v))

    return d


if __name__ == '__main__':
    ans = dijkstra(0, g)
    print(ans[-1])

代码中把100个门看做是0-99这100个节点,构建的是有向图。