寻找解决这个动态编程问题的提示
Looking for hints to solve this dynamic programming problem
我正在努力提高我在编程面试中解决问题的能力,并试图解决这个问题。我有一种感觉,它可以使用动态编程来解决,但递归关系对我来说并不明显。
为了选择前三位合唱团歌手,我只需使用蛮力。因为只有20 Choose 3 = 1140
种方法来挑选它们。起初我以为dp[a][b][c]
可以代表最短的歌曲,有三个合唱团歌手,还有剩余的呼吸a, b, c
。如果我可以用dp[a][b][c] = 1 + dp[a - 1][b - 1][c - 1]
来计算,但是当任何指数等于0
时应该怎么做,哪个合唱团歌手应该被替换。此外,我们不能重用dp
数组,因为假设在一个实例中,我们从具有呼吸a, b, c
的合唱团歌手开始,在第二个实例中d, e, f
.一旦计算了第一个实例并填充了dp
数组;第二个实例可能需要使用第一个实例计算的dp[i][j][k]
。由于此值首先取决于可用的合唱团歌手,并且两个实例中的可用歌手不同,因此在第二个实例中可能无法dp[i][j][k]
。这是因为最短的歌曲长度dp[i][j][k]
可能会使用合唱团歌手,在第二种情况下已经使用。
我没有解决这个问题的想法,任何地方都没有解决方案。有人可以给我一些提示来解决它吗?
问题陈述
我们有N
歌手,他们每个人都有一定的时间可以唱歌,一旦气喘吁吁,需要 1 秒钟才能恢复。他们可以唱的最小歌曲是多少,三个歌手一直在唱,他们三个同时唱完
?输入:
输入 3
这是这个想法。
在歌唱的每个点上,当前状态都可以通过歌手是谁、他们唱了多长时间以及哪些人目前气喘吁吁来表示。 从每个状态我们需要过渡到一个新的状态,即每个歌手气喘吁吁地准备再次唱歌,每个歌手唱歌都好少转一圈,可能会选择新的歌手。
天真地完成,最多有 20 位选择 3 位歌手,每个歌手都可以处于 10 种当前状态,再加上多达 2 位气喘吁吁的人。 这是您可以处于的 175560000 个组合状态。 这太多了,我们需要更聪明才能完成这项工作。
更聪明的是,我们没有20个可区分的歌手。 我们有 10 桶歌手,根据他们能唱多久。 如果一个歌手可以唱7圈,那么如果目前正在唱歌,他们不可能处于10个状态,而只能是7个。 我们不在乎两个人能唱7圈是在4和3转左转还是3和4,他们是一样的。 这引入了很多对称性。 一旦我们处理了所有的对称性,我们可能处于的状态数量就会从数亿减少到(通常(数万。
现在我们有一个 DP 的状态转换,这是dp[state1]
到dp[state2]
. 挑战在于生成一种状态表示形式,该表示形式利用了这些对称性,您可以将这些对称性用作数据结构的键。
更新:
代码的主循环看起来像这个 Python:
while not finished:
song_length += 1
next_states = set()
for state in current_states:
for next_state in transitions(state):
if is_finished(next_state):
finished = True # Could break out of loops here
else:
next_states.add(next_state)
current_states = next_states
大多数挑战是状态和transitions
功能的良好表示。
记忆方面的状态似乎与开始以来经过的时间无关。采取任何起始位置,
a, b, c
其中a, b, c
选择星等(每个歌手可以屏住呼吸多长时间(,a
是最小的星等。我们有
a, b, c
t = 0
它与:
0, b - a, c - a
t = a
因此,让我们将具有最小量级a
的初始状态定义为:
b, c, ba, ca
where ba = b - a
ca = c - a
t = a
从这里开始,状态的每次转换都是相似的:
new_a <- x
where x is a magnitude in
the list that can be available
together with b and c. (We only
need to try each such unique
magnitude once during this
iteration. We must also prevent
a singer from repeating.)
let m = min(new_a, ba, ca)
then the new state is:
u, v, um, vm
t = t + m
where u and v are from the
elements of [new_a, b, c] that
aren't associated with m, and um
and vm are their pairs from
[new_a, ba, ca] that aren't m,
subtracted by m.
记忆访问组合的状态只能是:
[(b, ba), (c, ca)] sorted by
the tuples' first element
如果达到的关联t
等于或高于该状态的最小值,我们可以在搜索中修剪分支。
例:
2 4 7 6 5
解决方案(自上而下阅读(:
4 5 6
7 4 5
2
国家:
u v um vm
5 6 1 2
t = 4
new_a = 7
m = min(7, 1, 2) = 1 (associated with 5)
7 6 6 1
t = 5
new_a = 4
m = min(4, 6, 1) = 1 (associated with 6)
4 7 3 5
t = 6
new_a = 5
m = min(5, 3, 5) = 3 (associated with 4)
5 7 2 2
t = 9
new_a = 2
m = min(2, 2, 2) = 2 (associated with 2)
5 7 0 0
t = 11
蟒蛇代码:
import heapq
from itertools import combinations
def f(A):
mag_counts = {}
for x in A:
if x in mag_counts:
mag_counts[x] = mag_counts[x] + 1
else:
mag_counts[x] = 1
q = []
seen = set()
# Initialise the queue with unique starting combinations
for comb in combinations(A, 3):
sorted_comb = tuple(sorted(comb))
if not sorted_comb in seen:
(a, b, c) = sorted_comb
heapq.heappush(q, (a, (b-a, b), (c-a, c), a))
seen.add(sorted_comb)
while q:
(t, (ba, b), (ca, c), prev) = heapq.heappop(q)
if ba == 0 and ca == 0:
return t
for mag in mag_counts.keys():
# Check that the magnitude is available
# and the same singer is not repeating.
[three, two] = [3, 2] if mag != prev else [4, 3]
if mag == b == c and mag_counts[mag] < three:
continue
elif mag == b and mag_counts[mag] < two:
continue
elif mag == c and mag_counts[mag] < two:
continue
elif mag == prev and mag_counts[mag] < 2:
continue
m = min(mag, ba, ca)
if m == mag:
heapq.heappush(q, (t + m, (ba-m, b), (ca-m, c), m))
elif m == ba:
heapq.heappush(q, (t + m, (mag-m, mag), (ca-m, c), b))
else:
heapq.heappush(q, (t + m, (mag-m, mag), (ba-m, b), c))
return float('inf')
As = [
[3, 2, 3, 3], # 3
[1, 2, 3, 2, 4], # 3
[2, 4, 7, 6, 5] # 11
]
for A in As:
print A, f(A)
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 首要问题的答案让值班员搞错了
- setlocale的C++土耳其字符串问题
- 如何重构类层次结构以避免菱形问题
- 寻找解决这个动态编程问题的提示
- 十进制到二进制的实现不能完全适用于我大学的检查器。问题或提示可能是什么
- Windows 凭据提示问题,CredUnPackAuthenticationBuffer 错误 50