UVa 10817 Headmaster's Headache (状压DP)

一个需要状态压缩的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
*/

你可能感兴趣的:(01背包,状压dp)