题目大意:
有n个任务,每个任务有一些要求,有m个人,每个人可以解决一些要求,问你,最多可以完成多少任务。
分析:
由于n和m很小,我们可以考虑状压DP,首先,预处理出来每个任务所需的人数组合,然后进行dp
dp[i][j]=max(dp[i-1][j-t[i][k]]+1,dp[i][j]);
dp[i][j]=max(dp[i][j],dp[i-1][j]);
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
using namespace std;
const int maxn = 10 + 10;
vector<int>a[maxn],b[maxn],t[maxn];
int n,m;
int vis[110];
int dp[maxn][2000];
void init()
{
for(int i=0;i<maxn;i++)
{
a[i].clear(); b[i].clear(); t[i].clear();
}
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
}
void solve()
{
for(int i=1;i<=n;i++)
{
for(int j=0;j<(1<<m);j++)
{
for(int l=0;l<a[i].size();l++)
vis[a[i][l]]=0;
int tot=0;
for(int k=1;k<=m;k++)
{
if(j&(1<<(k-1)))
{
tot++;
for(int l=0;l<b[k].size();l++)
{
// if(j==12) cout<<b[k][l]<<"***"<<endl;
vis[b[k][l]]=1;
}
}
}
if(tot>3) continue;
int cnt=0;
for(int l=0;l<a[i].size();l++)
{
// if(j==12)
// cout<<vis[a[i][l]]<<"..."<<endl;
if(vis[a[i][l]]) cnt++;
}
if(cnt==a[i].size())
{
t[i].push_back(j);
}
}
}
// for(int i=1;i<=n;i++)
// {
// cout<<i<<" ";
// for(int j=0;j<t[i].size();j++)
// {
// cout<<t[i][j]<<" ";
// }
// cout<<endl;
// }
}
void solve1(int kase)
{
for(int i=1;i<=n;i++)
{
for(int j=0;j<(1<<m);j++)
{
for(int k=0;k<t[i].size();k++)
{
if((j|t[i][k])==j) dp[i][j]=max(dp[i-1][j-t[i][k]]+1,dp[i][j]);
}
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
}
printf("Case #%d: %d\n",kase,dp[n][(1<<m)-1]);
}
int main()
{
int T,x,y;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++)
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
while(x--)
{
scanf("%d",&y);
a[i].push_back(y);
}
}
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
while(x--)
{
scanf("%d",&y);
b[i].push_back(y);
}
}
solve();
solve1(kase);
}
return 0;
}