[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];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章