POJ 2441 Arrange the Bulls 状压dp
题目链接:
http://poj.org/problem?id=2441
Arrange the Bulls
Memory Limit: 65536K
输入
In the first line of input contains two integers N and M (1 <= N <= 20, 1 <= M <= 20). Then come N lines. The i-th line first contains an integer P (1 <= P <= M) referring to the number of barns cow i likes to play in. Then follow P integers, which give the number of there P barns.
输出
Print a single integer in a line, which is the number of solutions.
样例输入
3 4
2 1 4
2 1 3
2 2 4
样例输出
4
题意
有n只牛,m个体育场,每只牛只会去若干个自己喜欢的体育场,现在要分配n只牛到n个不同的体育场,问总共有多少种分配方案。
题解
dp[i][j]表示分配前i只牛在状态为j的体育场的总方案数。
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef int LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=10000000000000000LL;
const double eps=1e-9;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=20;
int dp[2][1<<maxn];
///sumv统计二进制中1的个数
int sumv[1<<maxn];
int n,m;
bool mp[maxn][maxn];
void pre(){
clr(sumv,0);
rep(i,0,(1<<maxn)){
rep(j,0,maxn){
if(i&(1<<j)) sumv[i]++;
}
}
}
void init(){
clr(mp,0);
}
int main() {
pre();
while(scf("%d%d",&n,&m)==2&&n) {
init();
rep(i,0,n){
int cnt; scf("%d",&cnt);
while(cnt--){
int v; scf("%d",&v);
v--;
mp[i][v]=true;
}
}
int pre=0,cur=1;
clr(dp[cur],0);
///初始化
for(int j=0;j<m;j++){
if(mp[0][j]){
dp[cur][1<<j]=1;
}
}
for(int i=1;i<n;i++){
swap(pre,cur);
clr(dp[cur],0);
for(int j=0;j<m;j++){
if(mp[i][j]==0) continue;
for(int k=0;k<(1<<m);k++){
if(k&(1<<j)) continue;
dp[cur][k^(1<<j)]+=dp[pre][k];
}
}
}
int ans=0;
for(int i=0;i<(1<<m);i++){
if(sumv[i]==n) ans+=dp[cur][i];
}
prf("%d\n",ans);
}
return 0;
}
//end-----------------------------------------------------------------------