uva10817状压dp
题意:某校有s个课程m个教师和n个求职者,已知每人的工资和能教的课程,要求支付最少的工资使得每门课都至少有两名教师教学。在职教必须雇佣。
思路:d(i,s0,s1,s2)表示已经雇了i个人且授课状态为(s0,s1,s2),还需要多少钱。其中s0表示没有人授课的课程集合,s1表示只有一个人授课的课程集合,s2表示有2个老师授课的课程集合。(因为不知道要雇佣多少老师,所以状态为当雇佣了i人时还需要多少钱,而不是雇佣了i人花了多少钱)。
#include<bits/stdc++.h> using namespace std; #define maxn 150 #define maxs 10 #define inf 0x3f3f3f3f int m,n,s; int c[maxn],st[maxn]; int d[maxn][1<<maxs][1<<maxs]; int dp(int i,int s0,int s1,int s2) { if(i==m+n)return s2==((1<<s)-1)?0:inf; int&ans=d[i][s1][s2]; if(ans>=0)return ans;//如果ans被赋过值就不用再复制了,因为它代表d[][][],而d[][][]也代表一个dp函数的调用,参数相同,调用函数也相同。 ans=inf; if(i>=m)ans=dp(i+1,s0,s1,s2); int m0=st[i]&s0; int m1=st[i]&s1; s0^=m0; s1=(s1^m1)|m0; s2|=m1; ans=min(ans,dp(i+1,s0,s1,s2)+c[i]); return ans; } int main() { while(~scanf("%d%d%d",&s,&m,&n)&&m&&n&&s) { getchar(); memset(d,-1,sizeof(d)); memset(st,0,sizeof(st)); for(int i=0;i<m+n;i++) { string str; getline(cin,str); stringstream ss(str); int x,flag=1; while(ss>>x) { if(flag){flag=0;c[i]=x;continue;} x--; st[i]|=(1<<x); } } dp(0,(1<<s)-1,0,0); printf("%d\n",d[0][0][0]); } return 0; }