題目鏈接:點擊打開鏈接
題意:
有 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;
}