879. Profitable Schemes
題目網址:https://leetcode.cn/problems/profitable-schemes/
題意:集團里有
n
名員工, 他們可以完成各種各樣的工作創造利潤。第
i
種工作會產生profit[i]
的利潤, 它要求group[i]
名成員共同參與。如果成員參與了其中一項工作, 就不能參與另一項工作。選取一些工作, 這些工作需產生至少
minProfit
的利潤, 且工作的成員總數不得超過n
。有多少種方案可以選擇?因為答案很大, 所以返回結果 mod
$10^9 + 7$
的值即可。
Solution 1:
想法:利用 DP, 本題有兩種容量, 因此使用三維 DP
1. 定義狀態:
- 首先, 會在
group
、profit
前先加上一個0
, 代表什麼元素都沒有的狀態dp[i][j][k]
:前i
個工作中「恰好」選擇了j
個員工, 並滿足利潤為「至少」為k
的方案數2. 得到轉移方程:
- 第
i
個工作有「選 or 不選」兩種選擇:
若不選, 則要用前
i - 1
個工作完成選擇j
個員工, 並滿足最小利潤為k
➔dp[i][j][k] = dp[i - 1][j][k]
若要選, 假設第
i
個工作需person
個員工, 且能創造earn
利潤。則前i - 1
個工作需選擇j - person
個員工, 且至少需創造k - earn
利潤
➔dp[i][j][k] = dp[i - 1][j - person][k - earn]
- 由於我們定義的
dp[i][j][k]
是利潤「至少」為k
, 而不是利潤「恰好」為k
, 故上述的第三維應改為max(0, k - earn)
而不是k - earn
- 理由:若
earn > k
, 代表光是第i
個工作的利潤就超過要求k
了, 但我們題目要求的是「至少」, 也就是說如果要求利潤「至少」為k
, 則利潤為k
、k + 1
、k + 2
、… 也都是滿足條件的- e.g. 若
earn > k
, 則應選擇第i
個工作(假設沒超過人數上限), 並把該方案數加到dp[i][j - person][0]
中, 代表前i - 1
個工作就算利潤為0
也沒關係, 只要選了第i
個工作就能滿足利潤至少為k
➔
dp[i][j][k] = dp[i - 1][j - person][max(0, k - earn)]
3. 初始化:
dp[0][0][0]
:當沒有工作時, 選擇0
個員工, 並滿足利潤為「至少」為0
的方案數為1
(什麼都不選也是一種方案)
➔dp[0][0][0] = 1
題目要求的是所有工作中, 利潤至少為
minProfit
, 且工作的成員總數「不得超過」n
, 因此選擇的人數可以是0
、1
、…、n
, 故答案要對所有可能人數的方案數進行加總
➔res = (res + dp[m][j][minProfit])
, for0 ≤ j ≤ n
class Solution { |
- time:$O(m \cdot n \cdot minProfit)$ ➔ for loop
- space:$O(m \cdot n \cdot minProfit)$ ➔
dp
Solution 2:
想法:改進 Solution 1, 由於
dp[i][j][k]
只會用到上一列的狀態, 因此只需保存上一列的狀態即可
class Solution { |
- time:$O(m \cdot n \cdot minProfit)$ ➔ for loop
- space:$O(n \cdot minProfit)$ ➔
dp