# 1986. Minimum Number of Work Sessions to Finish the Tasks
###### tags: `Leetcode` `Medium` `DFS+Memorization`
Link: https://leetcode.com/problems/minimum-number-of-work-sessions-to-finish-the-tasks/
## 思路
重点复习!
### dp+backtracking
如果直接用backtracking会TLE
参考[这里](https://leetcode.com/problems/minimum-number-of-work-sessions-to-finish-the-tasks/discuss/1436811/C%2B%2BJavaPython-From-Straightforward-to-Optimized-Bitmask-DP-O(2n-*-n)-Clean-and-Concise)
Let ```dp(mask, remainTime)``` is the minimum of work sessions needed to finish all the tasks represent by mask (where $i$-th bit = 1 means ```tasks[i]``` need to proceed) with the remainTime we have for the current session.
We use mask as ```111...1111```, represent we need to process all n tasks.
We pass ```remainTime = 0```, which means there is no remain time for the current session; ask them to create a new session.
可以理解成从11111...111,0建tree tree的root是没有任何task所以dp返回0
### dp
状态压缩
dp[state]表示当mask为i时最少需要几个session
state是一个最大值是```1<<n```的mask 表示当下有几个task已经做了
dp[state]如果对应着多个session,那么它必然可以“拆分”成两个任务集subset与state-subset,然后对各自所需的session数目进行相加。所以我们需要遍历state的所有subset,找到最优的一种拆分。即dp[state]=min{dp[subset]+dp[state-subset]}。注意,上述的枚举子集的框架,所需要的时间复杂度是$o(3^n)$而不是$o(2^n)$
初始值:对于一些特定的任务组合state,如果总时间小于sessionTime,那么他们的dp[state]就是1. 其余的dp[state]我们都设置为无穷大。这需要花费2^n的时间预处理遍历所有的组合。。
利用枚举子集的模板:
```
for (int state=1; state<(1<<n); state++){
for (int subset=state; subset>0; subset=(subset-1)&state){
dp[state] = DoSomething(dp[subset]);
}
}
```
## Code
### dp+backtracking
```java=
class Solution {
public int minSessions(int[] tasks, int sessionTime) {
Integer[][] dp = new Integer[1<<tasks.length][sessionTime];
return backtracking(dp, tasks, sessionTime, (1<<tasks.length)-1, 0);
}
private int backtracking(Integer[][] dp, int[] tasks, int sessionTime, int mask, int remain){
if(mask==0) return 0;
if(dp[mask][remain]!=null) return dp[mask][remain];
int ans = tasks.length;
for(int i=0;i<tasks.length;i++){
if(((mask>>i)&1)==1){
int newMask = ~(1<<i)&mask;
if(tasks[i]<=remain){
ans = Math.min(ans, backtracking(dp, tasks, sessionTime, newMask, remain-tasks[i]));
}
else{
ans = Math.min(ans, backtracking(dp, tasks, sessionTime, newMask, sessionTime-tasks[i])+1);
}
}
}
return dp[mask][remain]=ans;
}
}
```
### dp
```java=
class Solution {
public int minSessions(int[] tasks, int sessionTime) {
int n = tasks.length;
int[] dp = new int[1<<n];
Arrays.fill(dp, Integer.MAX_VALUE/2);
for(int state=1; state<(1<<n); state++){
int sum=0;
for(int i=0; i<n; i++){
if(((state>>i)&1)==1){
sum += tasks[i];
}
}
if(sum<=sessionTime) dp[state]=1;
}
dp[0]=0;
for(int state=1; state<(1<<n); state++){
for(int substate=state; substate>=1; substate=(substate-1)&state){
dp[state] = Math.min(dp[state], dp[substate]+dp[state-substate]);
}
}
return dp[(1<<n)-1];
}
}
```