uva 10817 Headmaster's Headache 状压dp

//	uva 10817 Headmaster's Headache 状压dp
//
//	解题思路:
//
//		因为数据范围很小,所以想到状压dp。
//		
//		dp(i,s1,s2) 表示到前i个人,已经一门课只有一个老师教的集合
//		为s1,一门课有两个老师教的集合为s2.则状态转移为
//
//		dp(i,s1,s2) = min(dp(i+1,s1,s2),dp(i+1,s1',s2'))
//		前一项表示不聘用,后一项表示聘用,则s1'表示最新的只有一个
//		老师教的集合,s2'表示最新的有两个老师教的集合。
//
//		最后的结果当然就是d(1,0,0);
//
//		为了更加方便的实现,加入一个s0表示没有老师教的集合。
//		dp(i,s0,s1,s2);
//
//		在算新的s0,s1,s2时,定义一个m0,和一个m1表示加入该位教师
//		分别有一个老师,和两个老师教的集合
//		m0 = s0 & se[i];
//		m1 = s1 & se[i];
//		
//		s0 = s0 | m0;
//
//		s1 = (s1 ^ m1) | m0;
//
//		s2 = s2 | m1;


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 200;
const int INF = 0x1f1f1f1f;
int S,M,N;

int w[MAXN];
int se[MAXN];
int d[200][1<<9][1<<9];
bool vis[200][1<<9][1<<9];
inline bool isn(char c){
	if (c >= '0' && c <= '9')
		return true;
	return false;
}

void input(){
	for (int i=1 ;i <= M + N;i++){
		scanf("%d",&w[i]);
		char s[30];
		gets(s);
		int n = strlen(s);
		se[i] = 0;
		for (int j=0;j<n;j++){
			if (isn(s[j])){
				se[i] |= (1<<(s[j] - '0'-1));
			}
		}
	}
}

int DP(int i,int s0,int s1,int s2){
	if (i == M + N + 1)
		return  s2 == (1<<S) - 1 ? 0 : INF;

	if (vis[i][s1][s2])
		return d[i][s1][s2];

	vis[i][s1][s2] = 1;

	int& ans = d[i][s1][s2];

	ans = INF;

	if (i > M)	ans = min(ans,DP(i+1,s0,s1,s2));

	int m0 = s0 & se[i];

	int m1 = s1 & se[i];

	s0 ^= m0;

	s1 = (s1 ^ m1) | m0;

	s2 |= m1;

	ans = min(ans,DP(i+1,s0,s1,s2) + w[i]);

	return ans;


}


void solve(){
	memset(vis,0,sizeof(vis));
	printf("%d\n",DP(1,(1<<S)-1,0,0));
}

int main(){

	//freopen("1.txt","r",stdin);

	while(scanf("%d%d%d",&S,&M,&N)!=EOF){
		if (S==0)
			break;
		input();
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值