题目链接:点击打开链接
题意:
有 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;
}