题意:给你n头牛以及m个房间,每头牛只可放在一些固定的房间,求每头牛都放置到房间中的方案数。
思路:用dp[i][j]表示第i头牛在状态j时的方案数,则,dp[i][j] += dp[i-1][k];其中k为前i-1头牛放置成状态k的方案数,要保证在放第i头牛的位置为0。这样写空间消耗太大,
故需要改成滚动数组。dp[cnt][x] += dp[1-cnt][k];x为第i头牛可以放到房间的状态。
将第二层的循环作为状态,可以节约更多时间。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef __int64 int64;
typedef long long ll;
#define M 100005
#define max_inf 0x7f7f7f7f
#define min_inf 0x80808080
#define mod 1000000007
int n , m , dp[2][1<<20];
vector<int> cow[25];
int Solve()
{
int i , j , k , up , cnt = 1;
int size = 1<<m;
memset(dp , 0 , sizeof dp);
dp[0][0] = 1;
for (i = 0 ; i < n ; i++)
{
memset(dp[cnt] , 0 , sizeof dp[cnt]);
for (k = 0 ; k < size ; k++)
{
if (!dp[1-cnt][k])continue;
int up = cow[i].size();
for (j = 0 ; j < up ; j++)
{
int temp = cow[i][j];
if (k&(1<<temp))continue;
int x = k+(1<<temp);
dp[cnt][x] += dp[1-cnt][k];
}
}
cnt = 1-cnt;
}
cnt = 1-cnt;
int ret = 0;
for (i = 0 ; i < size ; i++)
ret += dp[cnt][i];
return ret;
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
int i;
for (i = 0 ; i < n ; i++)cow[i].clear();
for (i = 0 ; i < n ; i++)
{
int q , x;
scanf("%d",&q);
while (q--)scanf("%d",&x),cow[i].push_back(x-1);
}
if (m < n)
printf("0\n");
else
printf("%d\n",Solve());
}
return 0;
}