LeetCode5856. 完成任务的最少工作时间段(状态压缩动态规划)

题目:

5856. 完成任务的最少工作时间段

给出N个任务需要执行的时间,以及执行机构连续工作的时间,输出最少需要执行几次“连续工作”

题解:

  • 方法一:模拟+剪枝

用 S(m) 表示,已安排 0~m 个任务,所有的安排情况(是个集合,集合每个元素,是各session已用时间)

在安排 第 m+1 个任务的时候,就在所有安排情况(即集合每个元素)中,尝试所有安排 m+1 的可能性

模拟所有可能的情况,时间复杂度为O\left ( N \times N^{^{N}} \right ),这是最坏情况

采取如下剪枝:

1-先安排时间长的任务:开头的时候安排情况可能性就少,后面发散的少

2-如果恰好凑成 sessionTime,存在最优解,其它情况不再保留了

3-所有安排情况,排序后加入集合,去重

这些剪枝用下来,最优情况是 O(N\times N),一般情况会稍多一点,不会多太多

  • 方法二:状态压缩动态规划

DP[m] 表示,m 状态下最少 session 数。m 是位图,表示每一个任务是否安排

状态转移:DP[m] = \min_{j\bigcap m == j \&\& cost(j)< sessionTime} (DP[m - j] + 1)

时间复杂度,大约O(2^N)

源码:

方法一:模拟+剪枝

56ms,15.6MB

class Solution:
    def findindex(a, m):
        for (i, n) in enumerate(a):
            if n <= m:
                return i
    def minSessions(self, tasks: list[int], sessionTime: int) -> int:
        tasks.sort(reverse=True)
        ans = {(tasks[0],)}
        for i in range(1, len(tasks)):
            t = tasks[i]
            newans = set()
            for p in ans:
                p = list(p)
                index = Solution.findindex(p, sessionTime - t)
                if index == None:
                    # 只能新开一个 session
                    p.append(t)
                    newans.add(tuple(p))
                elif p[index] == sessionTime - t:
                    # 恰好有一个 session 刚好用完
                    p[index] = sessionTime
                    p.sort(reverse=True)
                    newans.add(tuple(p))
                else:
                    # 其它情况,要遍历所有可能性了
                    for i in range(index, len(p)):
                        pp = p.copy()
                        pp[i] += t
                        pp.sort(reverse=True)
                        newans.add(tuple(pp))
                    p.append(t)
                    p.sort(reverse=True)
                    newans.add(tuple(p))
            ans = newans
        return min(len(p) for p in ans)

        
if __name__ == "__main__":
    print(Solution().minSessions(tasks = [1,2,3], sessionTime = 3))
    print(Solution().minSessions(tasks = [3,1,3,1,1], sessionTime = 8))
    print(Solution().minSessions(tasks = [1,2,3,4,5], sessionTime = 15))
    print(Solution().minSessions([2,3,3,4,4,4,5,6,7,10], 12))
    print(Solution().minSessions([1,2,2,3,4,5,6,6,7,8,8,8],15))

方法二:状态压缩动态规划

3904ms,15.4MB

class Solution:
    def minSessions(self, tasks: list[int], sessionTime: int) -> int:
        n = len(tasks)
        cost = [0] * (1 << n)
        for i in range(1, 1 << n):
            cost[i] = sum(tasks[x] for x in range(n) if (1<<x) & i)

        dp = [float('inf')] * (1 << n)
        dp[0] = 0
        for i in range(1, 1 << n):
            j = i
            while j:
                if cost[j] <= sessionTime:
                    dp[i] = min(dp[i], dp[i - j] + 1)
                j = (j - 1) & i
        return dp[-1]


        
if __name__ == "__main__":
    print(Solution().minSessions(tasks = [1,2,3], sessionTime = 3))
    print(Solution().minSessions(tasks = [3,1,3,1,1], sessionTime = 8))
    print(Solution().minSessions(tasks = [1,2,3,4,5], sessionTime = 15))
    print(Solution().minSessions([2,3,3,4,4,4,5,6,7,10], 12))
    print(Solution().minSessions([1,2,2,3,4,5,6,6,7,8,8,8],15))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值