Skip to content

Commit 3b97fcb

Browse files
author
robot
committed
go
1 parent 89cd865 commit 3b97fcb

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

problems/1494.parallel-courses-ii.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ xi != yi
6363

6464
> 一般 20 以内都可以,具体的时间复杂度和数据规模的关系可从[我的网站](https://leetcode-pp.github.io/leetcode-cheat/)中的复杂度速查表中查看。
6565
66+
再比如 [5289. 公平分发饼干](https://leetcode.cn/problems/fair-distribution-of-cookies/) 看下数据范围就大概知道很可能就是回溯或者状压 DP。
67+
6668
这道题是状压 DP,如果你对其不了解,可以看下我之前写的 [状压 DP 是什么?这篇题解带你入门](https://mp.weixin.qq.com/s/ecxTTrRvUJbdWwSFbKgDiw),这里一些细节不再赘述。
6769

6870
首先,我们需要用一个数据结构来存储课程之间的依赖关系。不妨使用 hashmap,这样可以在 $O(1)$ 的时间获取到一个课程的所有前置课程。
@@ -134,11 +136,17 @@ for (i = x; i != 0; i = (i - 1) & x) {
134136

135137
有了上面的铺垫就简单了。我们只需要枚举所有子集,对于每一个子集,我们考虑使用动态规划来转移状态。
136138

139+
定义 dp[studied] 为学习情况为 studied 的最少需要学期数。
140+
141+
那么转移方程为:
142+
137143
```py
138-
dp[i | sub] = min(dp[i | sub], dp[i] + 1)
144+
# 含义为我们可以选择在这一学期学习 sub,或者选择在下一学期学习 sub
145+
# dp[studied | sub] 就是两种选择的较小值
146+
dp[studied | sub] = min(dp[studied | sub], dp[studied] + 1)
139147
```
140148

141-
其中 i 为当前的学习的课程,sub 为当前可以学习的课程的子集。其中 i 和 sub 都是一个数字,每一位的 bit 为 0 表示无该课程,为 1 表示有该课程。
149+
其中 studied 为当前的学习的课程,sub 为当前可以学习的课程的子集。其中 studied 和 sub 都是一个数字,每一位的 bit 为 0 表示无该课程,为 1 表示有该课程。
142150

143151
## 关键点
144152

@@ -160,7 +168,7 @@ class Solution:
160168

161169
for fr, to in dependencies:
162170
neighbors[to - 1] |= 1 << (fr - 1)
163-
dp[0] = 0 # 启动 dp
171+
dp[0] = 0 # 表示什么都不学的情况需要 0 学期
164172
for i in range(1 << n):
165173
can = 0
166174
for j in range(n):
@@ -170,9 +178,10 @@ class Solution:
170178
can &= ~i
171179
sub = can
172180
while sub:
181+
# 可以学习 sub
173182
if bin(sub).count("1") <= k:
174183
dp[i | sub] = min(dp[i | sub], dp[i] + 1)
175-
sub = (sub - 1) & can
184+
sub = (sub - 1) & can # 快速跳到下一个子集(枚举子集优化)
176185
return dp[(1 << n) - 1]
177186

178187

0 commit comments

Comments
 (0)