题目大意:有S门课程,N名在职教师和M名求职者,每名在职教师或求职者都有自己能教的课程集合以及工资,要求花费尽量少的钱选择一些人,使得每门课程都有至少两人教。在职教师必须选。
可以把“每个课程已经分别有几个人教”作为状态来进行转移,每个人能教的课程集合作为“物品重量”,工资作为“价值”来更新dp值,类似01背包,每放进一个人,从后往前更新即可。
状态的表示可以用三进制编码,为了写起来舒服,我写了个结构体作为状态和编码转换的桥梁,也可以进行状态的“加法运算”,虽然速度比较慢就是了~~
有点想吐槽的是,出题人就不能把每个人能教的课程数量也放在输入里么?非逼得人家用getline嘛~~
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll N=8+2,inf=0x3f3f3f3f; 5 int k,n,m,d[(1<<(N*2))+10],co,mx; 6 string line; 7 struct D { 8 int a[N]; 9 int& operator[](int x) {return a[x];} 10 D(int x=0) { 11 memset(a,0,sizeof a); 12 for(int i=0; i<k; ++i,x/=3)a[i]=x%3; 13 } 14 D operator+(D& b) { 15 D ret; 16 for(int i=0; i<k; ++i)ret[i]=min(a[i]+b[i],2); 17 return ret; 18 } 19 operator int() { 20 int ret=0; 21 for(int i=k-1; i>=0; --i)ret=ret*3+a[i]; 22 return ret; 23 } 24 25 }; 26 27 int main() { 28 ios::sync_with_stdio(0); 29 while(cin>>k>>n>>m&&k) { 30 cin.ignore(); 31 memset(d,inf,sizeof d); 32 d[0]=0; 33 co=0,mx=pow(3,k)+0.5; 34 while(n--) { 35 getline(cin,line); 36 stringstream ss(line); 37 int x; 38 ss>>x; 39 co+=x; 40 D t; 41 while(ss>>x)t[x-1]=1; 42 for(int i=mx-1; i>=0; --i)if(!d[i])d[D(i)+t]=0; 43 } 44 for(int i=0; i<mx; ++i)if(!d[i])d[i]=co; 45 while(m--) { 46 getline(cin,line); 47 stringstream ss(line); 48 ss>>co; 49 int x; 50 D t; 51 while(ss>>x)t[x-1]=1; 52 for(int i=mx-1; i>=0; --i) { 53 d[D(i)+t]=min(d[D(i)+t],d[i]+co); 54 } 55 } 56 printf("%d\n",d[mx-1]); 57 } 58 return 0; 59 }
UVA - 10817 Headmaster's Headache (状压类背包dp+三进制编码)
原文地址:https://www.cnblogs.com/asdfsag/p/10380979.html
时间: 2024-10-24 00:51:40