Pku2441 Arrange the Bulls
题目
Description
Farmer Johnson's Bulls love playing basketball very much. But none of them would like to play basketball with the other bulls because they believe that the others are all very weak. Farmer Johnson has N cows (we number the cows from 1 to N) and M barns (we number the barns from 1 to M), which is his bulls' basketball fields. However, his bulls are all very captious, they only like to play in some specific barns, and don’t want to share a barn with the others. So it is difficult for Farmer Johnson to arrange his bulls, he wants you to help him. Of course, find one solution is easy, but your task is to find how many solutions there are. You should know that a solution is a situation that every bull can play basketball in a barn he likes and no two bulls share a barn.
Farmer Johnson的公牛队非常喜欢打篮球。 但他们中没有一个人愿意和其他公牛一起打篮球,因为他们认为其他公牛都很弱。 农民约翰逊有N头奶牛(我们将奶牛的数量从1到N)和M个谷仓(我们将谷仓从1到M编号),这是他的公牛篮球场。 然而,他的公牛都非常挑剔,他们只喜欢在一些特定的谷仓玩耍,并且不想与其他人共用一个谷仓。 所以Farmer Johnson很难安排他的公牛,他希望你能帮助他。 当然,找到一个解决方案很容易,但您的任务是找到有多少解决方案。 你应该知道一个解决方案是每个公牛都可以在他喜欢的谷仓里打篮球并且没有两头公牛共用一个谷仓。
Input
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.
在输入的第一行包含两个整数N和M(1 <= N <= 20,1 <= M <= 20)。 然后来N行。 第i行首先包含一个整数P(1 <= P <= M),指的是我喜欢玩的谷仓的数量。然后跟随P整数,它给出了P谷仓的数量。
Output
Print a single integer in a line, which is the number of solutions.
在一行中打印一个整数,即解决方案的数量。
Sample Input
3 4 //三头牛,四个Romm 2 1 4 //一号牛喜欢两个房间, 分别为1号,4号房间,下面类似 2 1 3 2 2 4
Sample Output
4 //有四种方式将这三头牛都安排到一个它们喜欢的房间去..注意一个房间只安排一头牛....
思路
很明显就是一道$dp$ 的题;
但是题目一个房间只能安排一头牛,所以我们得记下每个房间是否使用的状态;
那么就要用到状态压缩了,如果状压 $dp$ 用法有点不清楚的读者,可以看看 $状压dp入门$
可以设 $dp[i][k]$ 表示第 $i$ 头奶牛安排好时,房间的使用状态为 $k$, 的方案数
那么转移方程就是
$ dp[i][k]+=dp[i-1][k \oplus (1<<j-1))]; $
$i$ 是当前安排好的奶牛,$j$ 表示 $i$ 占用了哪个房间;
这样就$ok$了
代码
#include<bits/stdc++.h> #define re register typedef long long ll; using namespace std; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n,m; ll a[20][20]; ll dp[20][1<<20]; int main() { n=read(); m=read();//读入 for(re ll i=1;i<=n;i++) { ll x=read(); for(re ll j=1;j<=x;j++) { ll y=read(); a[i][y]=1;//记录每个奶牛喜欢哪个房间 } } for(re ll i=1;i<=m;i++) if(a[1][i]) dp[1][1<<(i-1)]=1;//初始化 for(re ll k=1;k<=(1<<m)-1;k++)//枚举房间使用状态 for(re ll i=2;i<=n;i++)//枚举奶牛 { for(re ll j=1;j<=m;j++)//枚举当前奶牛占用了哪个房间 if(a[i][j])//如果奶牛喜欢这个房间 { if(k&(1<<(j-1)))//要保证状态包涵占用的房间 dp[i][k]+=dp[i-1][k^(1<<(j-1))];//转移方程 // cout<<i<<" "<<j<<" "<<dp[i][k]<<endl; } } ll ans=0; for(re ll i=1;i<=(1<<m)-1;i++) ans+=dp[n][i];//统计总方案数 printf("%lld\n",ans);//输出 //return 0; }