状压dp2

[Algo] 状压dp2

1. 每个人戴不同帽子的方案数

// 1. 每个人戴不同帽子的方案数
// https://leetcode.cn/problems/number-of-ways-to-wear-different-hats-to-each-other/
int func1(int n, int m, vector<vector<int>>& people, int status, int cur, vector<vector<int>>& dp) {
    if (status == (1 << n) - 1) return 1;
    if (cur > m) return 0;
    if (dp[status][cur] != -1) return dp[status][cur];
    int ans = func1(n, m, people, status, cur + 1, dp) % MOD;
    for (int person : people[cur]) {
        if ((status & (1 << person)) == 0) {
            ans = (ans + func1(n, m, people, status ^ (1 << person), cur + 1, dp)) % MOD;
        }
    }
    dp[status][cur] = ans;
    return ans;
}
int func2(int n, int m, vector<int>& people, int status, int cur, vector<vector<int>>& dp) {
    if (status == (1 << n) - 1) return 1;
    if (cur > m) return 0;
    if (dp[status][cur] != -1) return dp[status][cur];
    int ans = func2(n, m, people, status, cur + 1, dp) % MOD, like_status = people[cur], rightOne;
    while (like_status) {
        rightOne = like_status & -like_status;
        if ((status & rightOne) == 0) {
            ans = (ans + func2(n, m, people, status ^ rightOne, cur + 1, dp)) % MOD;
        }
        like_status ^= rightOne;
    }
    dp[status][cur] = ans;
    return ans;
}
int numberWays(vector<vector<int>>& hats) {
    int n = hats.size(), m = 0;
    for (int i = 0; i < n; i++)
    for (int e : hats[i]) m = max(m, e);
    //vector<vector<int>> people(m + 1);
    vector<int> people(m + 1);
    for (int i = 0; i < n; i++)
    for (int e : hats[i]) people[e] |= (1 << i);
    vector<vector<int>> dp(1 << n, vector<int>(m + 1, -1));
    return func2(n, m, people, 0, 1, dp);
}

2. 好子集的数目

// 2. 好子集的数目
// https://leetcode.cn/problems/the-number-of-good-subsets/
int own[31] = { 
    0b0000000000, // 0
    0b0000000000, // 1
    0b0000000001, // 2
    0b0000000010, // 3
    0b0000000000, // 4
    0b0000000100, // 5
    0b0000000011, // 6
    0b0000001000, // 7
    0b0000000000, // 8
    0b0000000000, // 9
    0b0000000101, // 10
    0b0000010000, // 11
    0b0000000000, // 12
    0b0000100000, // 13
    0b0000001001, // 14
    0b0000000110, // 15
    0b0000000000, // 16
    0b0001000000, // 17
    0b0000000000, // 18
    0b0010000000, // 19
    0b0000000000, // 20
    0b0000001010, // 21
    0b0000010001, // 22
    0b0100000000, // 23
    0b0000000000, // 24
    0b0000000000, // 25
    0b0000100001, // 26
    0b0000000000, // 27
    0b0000000000, // 28
    0b1000000000, // 29
    0b0000000111  // 30
};
int func3(vector<int>& cnt, int cur, int status, vector<vector<int>>& dp) {
    if (dp[status][cur] != -1) return dp[status][cur];
    int ans;
    if (cur == 1) {
        ans = 0;
        if (status == 0) {
            ans = 1;
            for (int i = 0; i < cnt[cur]; i++) ans = (ans << 1) % MOD;
        }
    } else {
        ans = func3(cnt, cur - 1, status, dp);
        if (own[cur] != 0 && cnt[cur] != 0 && (own[cur] & status) == own[cur]) {
            ans = (ans + (long)func3(cnt, cur - 1, status ^ own[cur], dp) * cnt[cur]) % MOD;
        }
    }
    dp[status][cur] = ans;
    return ans;
}
int numberOfGoodSubsets(vector<int>& nums) {
    vector<int> cnt(31);
    for (int num : nums) {
        cnt[num]++;
    }
    int limit = 1 << 10;
    int ans = 0;
    vector<vector<int>> dp(limit, vector<int>(31, -1));
    for (int i = 1; i < limit; i++) {
        ans = (ans + func3(cnt, 30, i, dp)) % MOD;
    }
    return ans;
}

*3. 分配重复整数

// *3. 分配重复整数
// https://leetcode.cn/problems/distribute-repeating-integers/
// 时间复杂度为O(n * 3^m), n为nums中不同数字的个数, m为订单数
bool func4(vector<int>& cnt, vector<int>& sum, int status, int index, vector<vector<int>>& dp) {
    if (status == 0) return true;
    if (index == cnt.size()) return false;
    if (dp[status][index] != 0) return dp[status][index] == 1;
    bool ans = false;
    // 枚举status的所有真子集
    for (int j = status; j > 0; j = (j - 1) & status) {
        if (sum[j] <= cnt[index] && func4(cnt, sum, status ^ j, index + 1, dp)) {
            ans = true;
            break;
        }
    }
    if (!ans) {
        ans = func4(cnt, sum, status, index + 1, dp);
    }
    dp[status][index] = ans == true ? 1 : -1;
    return ans;
}
bool canDistribute(vector<int>& nums, vector<int>& quantity) {
    sort(nums.begin(), nums.end());
    vector<int> cnt;
    cnt.push_back(1);
    int n = nums.size();
    for (int i = 1; i < n; i++) {
        if (nums[i] == nums[i - 1]) cnt[cnt.size() - 1]++;
        else cnt.push_back(1);
    }
    int m = quantity.size();
    vector<int> sum(1 << m);
    // 下面这个枚举是生成quantity中的每个子集,所需要数字的个数
    for (int i = 0, v, h; i < m; i++) {
        v = quantity[i];
        h = 1 << i;
        for (int j = 0; j < h; j++) {
            sum[h | j] = sum[j] + v;
        }
    }
    vector<vector<int>> dp(1 << m, vector<int>(cnt.size()));
    return func4(cnt, sum, (1 << m) - 1, 0, dp);
}
posted @ 2025-03-25 15:53  yaoguyuan  阅读(7)  评论(0)    收藏  举报