// 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;
}
uva 10817 Headmaster's Headache 状压dp
最新推荐文章于 2017-09-07 19:58:17 发布