📜  门|门CS 2010 |问题 29(1)

📅  最后修改于: 2023-12-03 15:42:22.558000             🧑  作者: Mango

题目描述

在一条直线上有n个房间,每两个房间之间有一扇门。有些门是开着的,有些门是关着的。在每个房间停留的时间为1个单位时间,进入一扇门所需要的时间为0.5个单位时间。请问,从第一个房间出发,到最后一个房间,至少需要多少时间。

输入格式

第一行输入n(n<=1000), 接下来n个数,表示n-1个门,1表示开着,0表示关着。

输出格式

输出一个浮点数,表示从第一个房间出发到最后一个房间,所需要的最短时间,结果保留两位小数。

输入样例
5
1 1 1 0
输出样例
4.50
题解

这道题简单来说就是在一个有向无环图中,求从源点到汇点的最短路径。可以使用拓扑排序和动态规划来解决。由于题目是给出的有向图是n个房间之间的关系,在里面有关键的开门关闭门的关系。所以首先要把操作转化为有向图,这部分的操作就没什么难度了,只不过与出现的节点的编号有关,需要注意一下编号。

接着我们需要确定状态:因为我们要求的是从第一个节点开始到达最后一个节点的最短时间,所以可以定义:dp[i]表示从第一个房间出发,走到第i个房间所需要的最少时间。

状态转移方程为:我们考虑当前节点i能够从哪些节点到达,由于是有向无环图,所以可以通过反向扫描来确定;同时,在能够到达当前节点i之前,一定会经过其他的一个节点k,因而我们可以将这一部分的时间表示为dp[k]+0.5。将所有能够到达节点i的代价都计算出来,然后取最小值即可。如果当前节点i是关闭的,则无法到达,代价需要设成正无穷。这就是标准的动态规划状态转移方程。

最后得到的dp[n-1]即为所求答案。

代码实现
n = int(input())
state = list(map(int, input().split()))

INF = float('inf')
dp = [INF] * n
dp[0] = 0

for i in range(1, n):
    # j可以到达当前节点i
    for j in range(i):
        if state[i-1] == 1:
            dp[i] = min(dp[i], dp[j] + (i-j) * 0.5)
        else:
            dp[i] = INF

print('%.2f' % dp[-1])

注意:输出结果需要保留两位小数,可以使用字符串格式化输出实现。