poj2441 狀壓dp

題目鏈接:點擊打開鏈接


題意:

有 n 頭牛;

有 m 個棚;

農夫約翰想要把牛關進棚裏;

每頭牛不會分享同一個棚;

而且每頭牛都有自己喜歡的 p 個棚,其他棚都不喜歡;

問要這些牛關進棚可以有多少種方式;


理解:

狀態壓縮;

遞推式含義:dp[i] 表示有 __builtin_popcount(i) 頭牛已經關進棚的方式總數;

其中,__builtin_popcount(i) 表示 i 的二進制的 1 的個數;

遞推式:dp[i | (1 << k)] += dp[i];

其中,第 k 頭牛未進棚;

初始值:dp[0] = 1;

沒有牛在棚是一種方式;


代碼如下:


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int MIN_INF = 1e-7;
const int MAX_INF = (1e9) + 7;

#define X first
#define Y second

int dp[(1 << 20) + 10];
int d[30][30];

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        int p;
        cin >> p;
        while (p--) {
            int b;
            cin >> b;
            d[i][b - 1] = 1;
        }
    }

    dp[0] = 1;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < (1 << 20); ++j) {
            if (__builtin_popcount(j) == i) {
                for (int k = 0; k < m; ++k) {
                    if ((j & (1 << k)) == 0 && d[i][k] == 1) {
                        dp[j | (1 << k)] += dp[j];
                    }
                }
            }
        }
    }

    int ans = 0;
    for (int i = 0; i < (1 << m); ++i) {
        if (__builtin_popcount(i) == n) {
            ans += dp[i];
        }
    }
    cout << ans << endl;

    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章