有爱的搜索题。
我们可以把每个任务所有满足条件的分人方式记录下来。由于人数很少可以用位运算。
按起始时间排序,由于只是改变了原序列对任务分配时的编号,所以用myp标记一下即可。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define pb(a) push_back(a)
int n,m;
int task[20][20];
struct node
{
int need,val,st,ed,id;
}save[100];
long long ans;
long long kind[20][2048];
int tim[100],myp[100],sum[100];
void dfs(int now,int val)
{
if(val>ans)
{
ans=val;
}
if(now>m) return ;
dfs(now+1,val);
bool flag;
int tmp[20];
for(int j=1;j<=n;j++) tmp[j]=tim[j];
for(int i=1;i<=kind[myp[now]][0];i++)
{
flag=true;
for(int j=1;j<=n;j++)
{
if( (kind[myp[now]][i]>>(j-1))&1)
{
if(tim[j]<save[now].st)
{
tim[j]=save[now].ed;
}
else
{
flag=false;
break;
}
}
}
if(flag)
{
dfs(now+1,val+save[now].val);
}
for(int j=1;j<=n;j++) tim[j]=tmp[j];
}
}
bool cmp(node aa,node bb)
{
return aa.st<bb.st;
}
bool judge(int num)
{
if(sum[num]==save[num].need) return true;
return false;
}
int main()
{
int a,b,c;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
for(int j=1;j<=a;j++)
{
scanf("%d",&b);
task[i][b]=1;
}
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&save[i].st,&save[i].ed,&save[i].need,&save[i].val);
save[i].id=i;
}
int k;
for(int i=1;i<=(1<<n)-1;i++)
{
k=0;
for(int j=1;j<=m;j++)
sum[j]=0;
for(int j=1;j<=n;j++)
{
if( (i>>(j-1))&1 )
{
k++;
for(int t=1;t<=m;t++)
{
if(task[j][t])
{
sum[t]++;
}
}
}
}
for(int j=1;j<=m;j++)
{
if(judge(j))
{
if(sum[j]!=k) continue;
kind[j][0]++;
kind[j][kind[j][0]]=i;
}
}
}
sort(save+1,save+1+m,cmp);
for(int i=1;i<=m;i++)
{
myp[i]=save[i].id;
//printf("%d\n",myp[i]);
}
dfs(1,0);
printf("%lld\n",ans);
return 0;
}