没写出来的原因多半是平时自己练太少了,其实很水的一个状压
题解:预处理出每个地方可以有哪些人组合完成
dp[i][j]就表示前i个人在状态j的最大完成数量。
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <sstream>
#define mod 1000000007
#define INF 0x3f3f3f3f
#define fuck() (cout << "----------------------------------------" << endl)
using namespace std;
const int maxn = 2000 + 10;
int n,m;
vector <int> ans[25];
vector <int> vec[25];
vector <int> peo[25];
int dp[20][1 << 10];
bool vis[105];
int main()
{
int T, kases = 1;
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
for(int i=0; i<25; i++)
{
vec[i].clear();
peo[i].clear();
ans[i].clear();
}
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
{
int num;
scanf("%d",&num);
while(num--)
{
int a;
scanf("%d",&a);
vec[i].push_back(a);
}
}
for(int i=0; i<m; i++)
{
int num;
scanf("%d",&num);
while(num--)
{
int a;
scanf("%d",&a);
peo[i].push_back(a);
}
}
for(int i=0; i<n; i++)
{
for(int j=0; j<(1<<m); j++)
{
bool ok = true;
int cnt = 0;
memset(vis,false,sizeof(vis));
for(int k=0; k<m; k++)
{
if(j & (1 << k))
{
for(int t=0; t<peo[k].size(); t++)
vis[peo[k][t]] = true;
cnt++;
}
}
if(cnt > 3) continue;
for(int t=0; t<vec[i].size(); t++)
if(!vis[vec[i][t]]) ok = false;
if(ok) ans[i].push_back(j);
}
}
for(int i=1; i<=n; i++)
{
for(int j=0; j<(1 << m); j++)
{
for(int t=0; t<ans[i-1].size(); t++)
{
if((j|ans[i-1][t]) == j)
dp[i][j] = max(dp[i][j], dp[i-1][j ^ ans[i-1][t]] + 1);
}
dp[i][j] = max(dp[i][j], dp[i-1][j]);
}
}
printf("Case #%d: %d\n",kases++, dp[n][(1 << m) - 1]);
}
}