題意:給你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;
}