状压DP UVA 10817 Headmaster's Headache

时间:2023-03-10 03:16:38
状压DP UVA 10817 Headmaster's Headache

题目传送门

 /*
题意:学校有在任的老师和应聘的老师,选择一些应聘老师,使得每门科目至少两个老师教,问最少花费多少
状压DP:一看到数据那么小,肯定是状压了。这个状态不好想,dp[s1][s2]表示s1二进制表示下至少有1位老师的科目集合
s2表示至少有2位老师的科目集合所花费的最小金额,状态转移方程(01):dp[t1][t2]=min(dp[t1][t2],dp[j][k]+c[i]);
j,k为当前两个集合,t1,t2为转移后的集合,另外求t1,t2用到了& |位运算 1&1 == 1 1 & 0 == 0 0 & 0 == 0
最后,学习了不知道数字多少个时应该用字符串整行读入
  详细解释
*/
/************************************************
* Author :Running_Time
* Created Time :2015-8-10 14:44:30
* File Name :UVA_10817.cpp
************************************************/ #include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std; #define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int MAXN = ;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + ;
int c[MAXN], p[MAXN], cnt[];
int dp[(<<)+][(<<)+];
int s, m, n;
int mxs;
int sum, st1, st2; int work(void) {
memset (dp, INF, sizeof (dp));
dp[st1][st2] = sum;
for (int i=m+; i<=m+n; ++i) {
for (int j=mxs; j>=; --j) {
for (int k=mxs; k>=; --k) {
if (dp[j][k] == INF) continue;
int t1 = (p[i] | j); int t2 = (p[i] & j) | k;
dp[t1][t2] = min (dp[t1][t2], dp[j][k] + c[i]);
}
}
}
return dp[mxs][mxs];
} int main(void) { //UVA 10817 Headmaster's Headache
while (scanf ("%d%d%d", &s, &m, &n) == ) {
if (!s) break; memset (cnt, , sizeof (cnt));
memset (p, , sizeof (p));
sum = , st1 = st2 = ; mxs = ( << s) - ;
string str;
for (int i=; i<=m+n; ++i) {
scanf ("%d", &c[i]);
getline (cin, str);
for (int j=; str[j]; ++j) {
if (isdigit (str[j])) {
int x = str[j] - '';
p[i] |= << (x - );
if (i <= m) ++cnt[x-];
}
}
if (i <= m) {
sum += c[i]; st1 |= p[i];
}
}
for (int i=; i<s; ++i) {
if (cnt[i] > ) st2 |= ( << i);
} printf ("%d\n", work ());
} return ;
}