简介:
招聘一定的老师,使得每门课有至少两个人教
分析:
状压dp
状态设计为:f[i][s1][s2] 表示考虑了前i个人,恰有一个人教的课程的课程集合为s1,有至少两个人教的集合为s2,最小花费为多少
状态转移:
dp过程是通过记忆化搜索完成的
f[i][s1][s2]=min{f[i+1][s1][s2],c[i]+f[i+1][s1’][s2’]}
s1’,s2’表示应聘第i个老师后的教课状态
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int INF=1<<20;
int er[9]={0,1,2,4,8,16,32,64,128};
int n,m,s,c[150],t[150],s1,s2;
int f[130][130][130];
int doit(int i,int s0,int s1,int s2) //s0没有老师教的课,s1只有一个老师教的课,s2有至少两个老师教的课
{
if (i==n+m)
return s2==(1<<s)-1?0:INF; //能不能使所有课都有两个人教
int &ans=f[i][s1][s2]; //记忆化
if (ans>=0) return ans;
ans=INF;
if (i>=m) //不招聘第i个新老师
ans=doit(i+1,s0,s1,s2);
int m0=t[i]&s0; //在没有人教的课中,新老师可以教的课
int m1=t[i]&s1; //在有一个人教的课中,新老师可以教的课
s0^=m0;
s1^=m1; s1|=m0;
s2|=m1;
ans=min(ans,c[i]+doit(i+1,s0,s1,s2));
return ans;
}
int main()
{
while (scanf("%d%d%d",&s,&m,&n)!=EOF&&s)
{
memset(t,0,sizeof(t));
for (int i=0;i<n+m;i++)
{
scanf("%d",&c[i]);
char ch;
scanf("%c",&ch);
while (ch!='\n')
{
if (ch==' '){
scanf("%c",&ch);
continue;
}
t[i]|=er[ch-'0']; //每个老师能教的课
scanf("%c",&ch);
}
}
memset(f,-1,sizeof(f));
printf("%d\n",doit(0,(1<<s)-1,0,0)); //(1<<s)-1 表示一开始所有课都没有教
}
return 0;
}