题目链接:uva 10817
题意:
某个学校师资力量不够,要招收新的老师,第一行给出s、m、n,现在在任的老师有m个,然后给出m行表示每个老师的信息,分别是该老师的工资,以及可教授的课程(个数不一定),然后在n行表示可招收的老师信息,同样是工资和课程,s表示该学校开售的课程,问,最少花多少钱可以使得该学校开设的s个课程每个课程至少有两个老师任教。
ps:现任的老师全部交,一个老师不管交多少课程,工资都是那些。
思路:
三进制状压dp,先求出现任老师的状态,然后预处理每个预招老师的状态,然后类似分组背包即可。不过得注意的是求状态的时候不能有进位操作产生,因为一个课程也可以有多个老师交,而这一位的状态应该还是2,卡了我好久。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define maxn 1005 #define MAXN 20005 #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 typedef long long ll; using namespace std; int n,m,ans,cnt,tot,flag; int s,state,cost,dp[10000],fac[10]; int w[105],ss[105]; char cs[100]; void solve() { int i,j,t; memset(dp,0x3f,sizeof(dp)); for(i=0;i<fac[s];i++) { int flg=1; for(int k=0;k<s;k++) { if((i/fac[k])%3>(state/fac[k])%3) flg=0; } if(flg) dp[i]=cost; } for(j=1; j<=n; j++) { for(i=fac[s]-1; i>=0; i--) { int x=0; for(int k=0;k<s;k++) { t=max(0,(i/fac[k])%3-(ss[j]/fac[k])%3); x+=t*fac[k]; } dp[i]=min(dp[i],dp[x]+w[j]); } } ans=dp[fac[s]-1]; } int main() { int i,j,t; fac[0]=1; for(i=1; i<=8; i++) { fac[i]=fac[i-1]*3; } while(~scanf("%d%d%d",&s,&m,&n)) { if(s==0) break ; gets(cs); state=cost=0; for(i=1; i<=m; i++) { gets(cs); cnt=t=0; for(j=0; ; j++) { if(cs[j]>='0'&&cs[j]<='9') { t=t*10+cs[j]-'0'; } else { if(t) { cnt++; if(cnt==1) cost+=t; else { if((state/fac[t-1])%3<2) state+=fac[t-1]; } t=0; } if(cs[j]=='\0') break ; } } } for(i=1; i<=n; i++) { gets(cs); cnt=t=ss[i]=0; for(j=0; ; j++) { if(cs[j]>='0'&&cs[j]<='9') { t=t*10+cs[j]-'0'; } else { if(t) { cnt++; if(cnt==1) w[i]=t; else ss[i]+=fac[t-1]; t=0; } if(cs[j]=='\0') break ; } } } solve(); printf("%d\n",ans); } return 0; } /* 2 2 3 10000 1 20000 2 2000 1 40000 1 2 300 2 2 2 2 10000 1 2 20000 2 1 30000 1 2 40000 1 2 0 0 0 */