一个需要状态压缩的0-1背包。dp[i][j]中第一维表示每个学科有没有第一个老师教,第二维表示每个学科有没有第二个老师教,这两个信息是要状压的。
对于0-1背包,如果写成dp[i]=max(dp[i],dp[i-w[k]]+c[k])的形式,就要判断i-w[k]是不是大于等于0。在这道题里判断相似的问题有些麻烦,所以写成dp[i+w[k]]=max(dp[i+w[k]],dp[i]+c[k])的形式。
代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #include <algorithm> #define INF 10000000 int dp[260][260]; int S,M,N; int vis[105]; int C[105]; int main(){ while(~scanf("%d%d%d",&S,&M,&N)){ if(!S) break; int ALL=(1<<S); memset(dp,0x3f,sizeof(dp)); memset(vis,0,sizeof(vis)); int sum=0; int ini[10]; memset(ini,0,sizeof(ini)); for(int i=1;i<=M;i++){ int cost,t; char c; scanf("%d",&cost); sum+=cost; while(1){ scanf("%d%c",&t,&c); ini[t-1]++; if(c=='\n') break; } } int u,v; u=0;v=0; for(int i=0;i<S;i++){ if(ini[i]==1){ u|=(1<<i); } else if(ini[i]>=2){ u|=(1<<i); v|=(1<<i); } } dp[u][v]=sum; for(int i=1;i<=N;i++){ scanf("%d",&C[i]); int t;char c; while(1){ scanf("%d%c",&t,&c); t--; vis[i]|=(1<<t); if(c=='\n') break; } } for(int i=1;i<=N;i++){ for(int j=ALL-1;j>=0;j--){ for(int k=j;k>=0;k--){ dp[j|vis[i]][k|(j&vis[i])]=min(dp[j|vis[i]][k|(j&vis[i])],dp[j][k]+C[i]); } } } printf("%d\n",dp[ALL-1][ALL-1]); } return 0; } /* 3 1 3 10 1 100 1 2 3 20 1 2 3 30 2 3 2 0 2 10 1 2 20 1 2 */