又是一道看题就懵逼抄题解的题
每个状态可以用三个集合表示,没有人教科目集,只有一个人教科目集,至少两人教科目集,可以发现任意两个集合可以推出来第三个,为了方便我选了前两个
然后另一维是当前已经对前i个老师做完决策了,对每个老师有选和不选两种决策,但是前M个必须选。
所以当没人教科目集和只有一人教科目集为空集时和所有老师都考虑完时为边界
怒交一发,不出意外又WA。然后看了一眼debug不过的数据发现,有一种情况是固定教师还没考虑完时已经到边界可以返回零了,但这时要继续向下知道所有固定教师都考虑完,无论他们是否有用都必须聘用
这个读入也是贼坑了,getsCE,只能一个字符一个字符读
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#define INF (21000010)
using namespace std;
int S,M,N,T[2020],val[2020],A[2020],dp[125][(1<<8)+5][(1<<8)+5];
bool vis[125][(1<<9)+5][(1<<9)+5];
void InIt(){
memset(T,0,sizeof(T));
int i,x=0; char ch;
while (1){
ch=getchar();
if (ch=='\n') break;
if (ch!=' ') x=(x<<3)+(x<<1)+ch-'0';
else if (x) T[++T[0]]=x,x=0;
}
if (x) T[++T[0]]=x;
}
int Dfs(int i,int s0,int s1){
int &ans=dp[i][s0][s1];
if (vis[i][s0][s1]) return ans;
vis[i][s0][s1]=1;
if (!s0&&!s1&&i>M) return ans=0;
//坑点,此处不能直接退,因为固定教师一定要用
if (i==N+M+1) return ans=INF;
if (i>M) ans=min(ans,Dfs(i+1,s0,s1));
int m0=A[i]&s0,m1=A[i]&s1;
//m0:能使没人教变成有一个人教的科目集合
//m1: 能使一个人教变成至少两个人教的科目集合
s0^=m0; s1^=m1; s1|=m0;
ans=min(ans,Dfs(i+1,s0,s1)+val[i]);
return ans;
}
void Work(){
int i,j;
memset(A,0,sizeof(A));
memset(vis,0,sizeof(vis));
memset(dp,127/3,sizeof(dp));
for (i=1;i<=M+N;i++){
InIt();
val[i]=T[1];
for (j=2;j<=T[0];j++) A[i]|=(1<<(T[j]-1));
}
printf("%d\n",Dfs(1,(1<<S)-1,0));//写成(1<<M)-1
}
int main(){
while (1){
scanf("%d %d %d",&S,&M,&N);
if (!S&&!M&&!N) break;
char ch=0;
while (ch!='\n') ch=getchar();
Work();
}
}