[LeetCode 双周赛25] 4. 每个人戴不同帽子的方案数(状态压缩、动态规划、巧妙解法)

1. 题目来源

链接:1434. 每个人戴不同帽子的方案数

2. 题目说明

在这里插入图片描述
在这里插入图片描述

3. 题目解析

方法一:状压dp+巧妙解法

又是一道状压 dp 问题。一开始直观的思路是直接对帽子进行性状态压缩,让人去找帽子。但是这个帽子的数量太多了,不利用直接进行状态压缩,但是人的数量很少,可以对人进行状态压缩,让帽子去找人。思路如下:

  • dp[i][bits] 前 i 顶帽子确定了归属,人带帽子的状态 bits 的方案数
  • dp[i][bits]->dp[i+1][new_bits] 转态转移两种情况:
    • 我们将 i+1 顶帽子,给某个人 jnew_bits = bits | (1<<j),前提是 j 喜欢帽子 i + 1(bits>>j) & 1 = 0
    • i+1 顶帽子不给人带,bits=new_bits

其它相关注释也写在代码里了,便于查看。我感觉状压 dp 就选择数据小的那一维进行状压就可了。但目前却是还是理解不到位的。

参见代码如下:

// 执行用时 :508 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :7.9 MB, 在所有 C++ 提交中击败了100.00%的用户

const int MOD = 1e9 + 7;
int dp[45][1<<10];

class Solution {
public:
    int numberWays(vector<vector<int>>& hats) {
        int n = hats.size(); 
        int lim = 1 << n;
        for (int i = 0; i <= 40; ++i) for (int j = 0; j < lim; ++j) dp[i][j] = 0;
        dp[0][0] = 1;

        for (int h = 1; h <= 40; ++h) {             // 分配帽子
            for (int s = 0; s < lim; ++s) {         // 当前人带帽子的状态
                if (dp[h - 1][s]  == 0) continue;   // 在模下不会对结果产生影响,直接continue
                for (int i = 0; i < n; ++i) {       // 否则尝试让i人带这个帽子
                    bool flag = false;
                    for (auto e : hats[i]) if (e == h) flag = true;     // 查看是否为i人所喜欢的帽子
                    if (flag == false) continue;    // 不喜欢查看下一个人
                    if ((s >> i) & 1) continue;     // i这个人不能带过帽子
                    int news = s | (1 << i);        // i带这个帽子,并更新它的状态
                    dp[h][news] = (dp[h][news] + dp[h - 1][s]) % MOD;   // 第h顶帽子有人带了状态转移
                }
            }
            for (int s = 0; s < lim; ++s) {         // 若第h顶帽子没人带状态转移
                dp[h][s] = (dp[h][s] + dp[h - 1][s]) % MOD;
            }
        }
        return dp[40][lim - 1];
    }
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值