状压DP_hard_1434_每个人戴不同帽子的方案数

题目描述

在这里插入图片描述

思路

解法一:状压DP : T i m e O ( m n 2 n ) Time O(mn2^n) TimeO(mn2n)

Reference

  • 其中 m为 帽子数量,这里是40,n是人数
class Solution:
    def numberWays(self, hats: List[List[int]]) -> int:
        # 让人戴帽子的嵌套列表 -> 把帽子送人的字典
        d = {k: set() for k in range(1, 41)}
        n = len(hats)
        for i in range(n):
            for hat in hats[i]:
                d[hat].add(i)

        # 构造 dp table
        cols = 2 ** n
        # 第 0 行,没有可用帽子时,方案数为 0
        dp = [[0] * cols for i in range(41)]  # 41行 n列的 matrix
        # 没有可用帽子,但又不用送帽子,方案数为 1
        dp[0][0] = 1

        for i in range(1, 41):
            for j in range(cols):
                # 情况一:不送帽i
                dp[i][j] += dp[i - 1][j]
                # 情况二:送帽i给人k
                for k in d[i]:
                    # 当前戴帽状态 j 中,人k需要帽子
                    if j & 1 << k != 0:
                        # 用 j ^ 1 << k 找到之前人k不戴帽子时的状态
                        dp[i][j] += dp[i - 1][j ^ 1 << k]

        return dp[-1][-1] % (10 ** 9 + 7)
  • 调优:可以用滚动数组 将dp matrix 降维成 dp list

方法二:状压+dfs

class Solution:
    def numberWays(self, hats: List[List[int]]) -> int:
        L = len(hats)
        @lru_cache(typed=False, maxsize=128000000)
        def dfsp(i,person):
            if person == (2**L)-1:
                return 1
            if i == 41:
                return 0
            res = 0
            #给第i个帽子找人, i是帽子,j是人
            for j in range(L):
                # 如果这个人没有帽子,并且可以带这个帽子,就找下一个帽子
                if not person & (1 << j) and i in hats[j]:
                    res += dfsp(i + 1, person | (1 << j))
            # 不一定要选这个帽子,可以直接选下一个帽子
            res += dfsp(i + 1, person)
            return res
        ans = dfsp(1, 0) % 1000000007
        return ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值