【经典题目】每个人戴不同帽子的方案数——从人对应物品到物品对应人的转换思路

第25场双周赛
第四题
在这里插入图片描述

这道题可以按照回溯法的思路暴力结局,列举出来所有的可能佩戴方法。但是这种方法的复杂度较高,并不是最优解。

这里我们换一种思路,同样是回溯法,相比于给每个人佩戴帽子,每个人都有很多种选择,不如把问题转变成给帽子选择人。一共40顶帽子,每一个帽子都分为有人戴和没人戴。且只能被一个人拥有。因此我们考虑考虑变成背包问题,首先依次遍历40顶帽子(戴or不戴),在内层循环中遍历每一个人。

40顶帽子,最多10个人,这里有两个维度的数据。做如果回溯的话,有两条路径:
(1)10个人,每个人依次选择一个帽子。
(2)40顶帽子,每个帽子尝试分配给每个可能的人。

这里前一个状态和后一个状态之间是有关联的。对于不同的路径
(1)前一个状态选过的帽子,后一个状态不能再选了。
(2)前一个状态选过的人,后一个状态不能再选了。
但是因为集合不可hash,所以集合不能作为我们状态记录缓存的key。同时,我们也需要一个能在常数时间判断数据是否可用的方式,这里可以用另一种方式,bit位。对于不同的路径:
(1)第n个bit位代表帽子是否被选过
(2)第n个bit位代表人是否已经有帽子了
这个时候路径(2)的优势就体现了,因为最多10个人,可以在一个32bit的整数内表示,而路径(1)要40个bit。

同时,我们采用1<<n来表示出来40顶帽子的状态,初始全部是0。检验第k顶帽子有没有人戴只需要判断(1<<(k-1)&hat

from functools import lru_cache

class Solution:
    def numberWays(self, hats: List[List[int]]) -> int:
        # 总人数
        n = len(hats)
        dic = collections.defaultdict(list)
        for i in range(n):
            for hat in hats[i]:
                dic[hat].append(i)

        @lru_cache(None)        
        def dp(cur, pos):
            # cur 代表当前轮到第cur顶帽子可供选择
            # pos 代表当前戴帽的人有哪些,为二进制压缩状态形式
            # 首先,如果当前所有人都
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值