状压DP Pku2441 Arrange the Bulls

     本人水平有限,题解不到为处,请多多谅解

         本蒟蒻谢谢大家观看

题目:传送门

Problem C: Pku2441 Arrange the Bulls

Time Limit: 2 Sec  Memory Limit: 512 MB
Submit: 157  Solved: 80
[Submit][Status][Web Board]

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
//有四种方式将这三头牛都安排到一个它们喜欢的房间去..注意一个房间只安排一头牛....

HINT

第一个疑点  : 1<<(v-1)&i  

意思是将i转化为二进制数后,令这个二进制数为kk。
则kk从右往左起的第v位跟1进行与运算,来判断kk的v位是否为1;若为1,则此位
已经用过;反之,则没有用过;

第二个疑点      :  1 << (v-1)^ i

  注:      1代表用过,0代表没用过;

意思是将i转化为二进制数后,令这个二进制数为kk。
则kk从右往左起的第v位跟1进行异或运算,来计算kk的第v位的值,若现在用过,
则以前一定没用过;反之,则以前一定用过;

code:

#include<bits/stdc++.h>
using namespace std;
//f[i][j]表示第i号谷仓的状态,1~j头奶牛已经选好的方案数 
int n,m,f[1<<20][21],a[21],sum[21][21],ans;
int main() 
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++) 
    {
        scanf("%d",&a[i]);
        for(int j=1; j<=a[i]; j++)
            scanf("%d",&sum[i][j]);
    }
    f[0][0]=1;//初始化:什么都不选的方案数为1 
    for(int j=1; j<=n; j++)//应该先枚举房间数量,再来看奶牛数量 
        for(int i=1; i<pow(2,m);i++)
            for(int k=1; k<=a[j]; k++) //第j号奶牛喜欢的房间数量 
            {
                int v=sum[j][k];//第j号奶牛喜欢的房间编号标记为 v 
                if(1<<(v-1)&i)//判断第 v号房间是否使用过 
                    f[i][j]+=f[i^1<<(v-1)][j-1];
                    //看第v号房间之前的状态以及1~(j-1)头奶牛以及选好的方案数 
            }
    for(int i=1;i<pow(2,m);i++)
        ans+=f[i][n];//表示第i号谷仓的状态,1~n头奶牛已经选好的方案数总和  
    printf("%d
",ans);
}
/*
3 4
2 1 4
2 1 3
2 2 4
*/
原文地址:https://www.cnblogs.com/nlyzl/p/11281593.html