📜  门|门CS 2012 |第 45 题(1)

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

题目描述

在一条长度为 $N$ 的直线道路上,有 $n$ 扇门,每扇门在直线上的位置用一个正整数 $a_i$ 表示,其中 $1\leq a_1 < a_2 < \cdots < a_n \leq N$。一开始所有门都是关闭的。有 $m$ 个人按顺序从位置 $1$ 出发,每个人都有一个能力值 $p_i$ ,当第 $i$ 个人经过位置 $a_i$ 时,他可以改变第 $a_i$ 扇门的状态,即如果该门开着则将它关闭,反之则将它打开。每个人只有一次机会改变门的状态,而且只能改变与自己位置相同的门的状态。最后在道路的左端设置了一块显示器,当某扇门被打开时,要求在显示器上输出该门处的位置 $a_i$。请你设计一种算法,使得所有扇门都能被打开,并且所有打开的门的位置按升序输出。如果有多组解,输出开门总次数最小的解。

解题思路

本题可以使用 $01$ 背包思想,对于每个人 $i$,设 $dp_i$ 表示经过前 $i$ 个人后开的最少的门数,并记录每次开门的位置,即用 $pre_{i,j}$ 记录状态 $dp_{i,j}$ 转移过程中开的门的位置。状态转移方程为

$$ dp_{i,j}=\min{dp_{i-1,j},dp_{i-1,j-1}+1} $$

其中当 $dp_{i,j}=dp_{i-1,j-1}+1$ 时,说明第 $i$ 个人需要开门,因此记录其开门的位置。最后输出 $dp_{m,n}$ 及其转移过程中开门的位置即可。

代码实现
def open_door(n, m, doors, people):
    dp = [[0 for _ in range(n+1)] for _ in range(m+1)]
    pre = [[[] for _ in range(n+1)] for _ in range(m+1)]
    for i in range(1, m+1):
        for j in range(i, n+1):
            dp[i][j] = dp[i-1][j]
            pre[i][j] = pre[i-1][j]
            if dp[i][j] > dp[i-1][j-1] + (doors[j] != (i % 2)):
                dp[i][j] = dp[i-1][j-1] + (doors[j] != (i % 2))
                pre[i][j] = pre[i-1][j-1] + [j]
    result = []
    for i in pre[m][n]:
        result.append(doors[i])
    return result
返回markdown格式

门|门CS 2012 |第 45 题

题目描述

在一条长度为 $N$ 的直线道路上,有 $n$ 扇门,每扇门在直线上的位置用一个正整数 $a_i$ 表示,其中 $1\leq a_1 < a_2 < \cdots < a_n \leq N$。一开始所有门都是关闭的。有 $m$ 个人按顺序从位置 $1$ 出发,每个人都有一个能力值 $p_i$ ,当第 $i$ 个人经过位置 $a_i$ 时,他可以改变第 $a_i$ 扇门的状态,即如果该门开着则将它关闭,反之则将它打开。每个人只有一次机会改变门的状态,而且只能改变与自己位置相同的门的状态。最后在道路的左端设置了一块显示器,当某扇门被打开时,要求在显示器上输出该门处的位置 $a_i$。请你设计一种算法,使得所有扇门都能被打开,并且所有打开的门的位置按升序输出。如果有多组解,输出开门总次数最小的解。

解题思路

本题可以使用 $01$ 背包思想,对于每个人 $i$,设 $dp_i$ 表示经过前 $i$ 个人后开的最少的门数,并记录每次开门的位置,即用 $pre_{i,j}$ 记录状态 $dp_{i,j}$ 转移过程中开的门的位置。状态转移方程为

$$ dp_{i,j}=\min{dp_{i-1,j},dp_{i-1,j-1}+1} $$

其中当 $dp_{i,j}=dp_{i-1,j-1}+1$ 时,说明第 $i$ 个人需要开门,因此记录其开门的位置。最后输出 $dp_{m,n}$ 及其转移过程中开门的位置即可。

代码实现
def open_door(n, m, doors, people):
    dp = [[0 for _ in range(n+1)] for _ in range(m+1)]
    pre = [[[] for _ in range(n+1)] for _ in range(m+1)]
    for i in range(1, m+1):
        for j in range(i, n+1):
            dp[i][j] = dp[i-1][j]
            pre[i][j] = pre[i-1][j]
            if dp[i][j] > dp[i-1][j-1] + (doors[j] != (i % 2)):
                dp[i][j] = dp[i-1][j-1] + (doors[j] != (i % 2))
                pre[i][j] = pre[i-1][j-1] + [j]
    result = []
    for i in pre[m][n]:
        result.append(doors[i])
    return result