UVa 10817 (状压DP + 记忆化搜索) Headmaster's Headache

题意:

一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师。

每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门。

要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少。

分析:

因为s很小,所以可以用状态压缩。

dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2。

在递归的过程中,还有个参数s0,表示还没有人教的科目的集合。

其中m0, m1, s0, s1, s2的计算用到位运算,还是个不错的练习。

 1 #include <cstdio>
 2 #include <string>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <sstream>
 6 using namespace std;
 7
 8 const int maxs = 8;
 9 const int maxn = 125;
10 const int INF = 1000000000;
11 int s, m, n, c[maxn], st[maxn], d[maxn][1<<maxs][1<<maxs];
12
13 int dp(int i, int s0, int s1, int s2)
14 {
15     if(i == m+n) return s2 == (1<<s)-1 ? 0 : INF;
16     int& ans = d[i][s1][s2];
17     if(ans >= 0) return ans;
18     ans = INF;
19     if(i >= m) ans = dp(i+1, s0, s1, s2);
20     int m0 = st[i]&s0, m1 = st[i]&s1;   //m0是该教师能教且现在没人教的科目,m1是能教且现在只有一个人教的集合
21     s0 ^= m0; s1 = (s1^m1)|m0; s2 |= m1;
22     ans = min(ans, c[i] + dp(i+1, s0, s1, s2));
23     return ans;
24 }
25
26 int main()
27 {
28     //freopen("in.txt", "r", stdin);
29     int x;
30     string line;
31     while(getline(cin, line))
32     {
33         stringstream ss(line);
34         ss >> s >> m >> n;
35         if(s == 0) break;
36
37         memset(st, 0, sizeof(st));
38         for(int i = 0; i < m+n; ++i)
39         {
40             getline(cin, line);
41             stringstream ss(line);
42             ss >> c[i];
43             while(ss >> x) st[i] |= (1 << (x-1));
44         }
45         memset(d, -1, sizeof(d));
46         printf("%d\n", dp(0, (1<<s)-1, 0, 0));
47     }
48
49     return 0;
50 }

代码君

UVa 10817 (状压DP + 记忆化搜索) Headmaster's Headache

时间: 2024-10-24 01:48:33

UVa 10817 (状压DP + 记忆化搜索) Headmaster's Headache的相关文章

UVa 1252 (状压DP + 记忆化搜索) Twenty Questions

题意: 有n个长为m的各不相同的二进制数(允许存在前导0),别人已经事先想好n个数中的一个数W,你要猜出这个数. 每次只可以询问该数的第K为是否为1. 问采用最优询问策略,则最少需要询问多少次能保证猜到. 比如有1100 和 0110两个数,只需要询问第一或第三位数是否为1,即可猜中,因此答案为1. 分析: d(s, a)表示已经询问了的集合s,在已经询问了的集合中W中为1的集合为a,还需要询问多少次. 如果下一次询问第k位,则询问次数为: 然后取所有k里的最小值即可. 预处理: 对于每个s和a

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje

状压DP+记忆化搜索 UVA 1252 Twenty Questions

题目传送门 1 /* 2 题意:给出一系列的01字符串,问最少要问几个问题(列)能把它们区分出来 3 状态DP+记忆化搜索:dp[s1][s2]表示问题集合为s1.答案对错集合为s2时,还要问几次才能区分出来 4 若和答案(自己拟定)相差小于等于1时,证说明已经能区分了,回溯.否则还要加问题再询问 5 */ 6 /************************************************ 7 * Author :Running_Time 8 * Created Time :

[JZOJ5398]:Adore(状压DP+记忆化搜索)

题目描述 小$w$偶然间见到了一个$DAG$. 这个$DAG$有$m$层,第一层只有一个源点,最后一层只有一个汇点,剩下的每一层都有$k$个节点. 现在小$w$每次可以取反第$i(1<i<n-1)$层和第$i+1$层之间的连边.也就是把原本从$(i,k_1)$连到$(i+1,k_2)$的边,变成从$(i,k_2)$连到$(i+1,k_1)$. 请问他有多少种取反的方案,把从源点到汇点的路径数变成偶数条? 答案对$998244353$取模. 输入格式 一行两个整数$m,k$. 接下来$m-1$行

uva 10626 Buying Coke (DP + 记忆化搜索)

Problem D Buying Coke Input: Standard Input Output: Standard Output Time Limit: 2 Seconds I often buy Coca-Cola from the vending machine at work. Usually I buy several cokes at once, since my working mates also likes coke. A coke in the vending machi

UVa 10599【lis dp,记忆化搜索】

UVa 10599 题意: 给出r*c的网格,其中有些格子里面有垃圾,机器人从左上角移动到右下角,只能向右或向下移动.问机器人能清扫最多多少个含有垃圾的格子,有多少中方案,输出其中一种方案的格子编号.格子编号是从 左上角第一个开始,一行一行的按自然数顺序编.起始行列是第一行第一列.所以例如一个格子的行列号为(ro,co),那么它的编号为bh=(ro-1)*column+co,其中column指这个格子有多少列.(我觉得原题里面有个错误,题目叙述倒数第二行应该是41(6,6)不是41(6,7)).

uva 10123 - No Tipping dp 记忆化搜索

这题的题意是 在双脚天平上有N块东西,依次从上面取走一些,最后使得这个天平保持平衡! 解题: 逆着来依次放入,如果可行那就可以,记得得有木板自身的重量. /************************************************************************* > File Name: 10123.cpp > Author: opas > Mail: [email protected] > Created Time: 2016年10月22日

UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)

题目链接:uva 1252 题意: 有n个长度为m的二进制串,每个都是不同的. 为了把所有字符串区分开,你可以询问,每次可以问某位上是0还是1. 问最少提问次数,可以把所有字符串区分开来. 思路来源于:点击打开链接 思路: m很小,可以考虑状态压缩. dp[s1][s2]表示询问的状态为s1时,此时能猜到状态包含s2时最小需要的步数. 当询问的几位=s2的二进制串小于2时就能区分出来了,dp[s1][s2]=0: 不能区分则再询问一次,s1|=(1<<k),如果问某位为0,则s2不变,问某位为

UVA - 10913Walking on a Grid(记忆化搜索)

题目:Walking on a Grid 题目大意:给出N * N的矩阵,每个格子里都有一个值,现在要求从(1,1)走到(n, n),只能往下,左,右这三个方向走,并且要求最多只能取k个负数,求这样的要求下能得到的走过格子的值之和最大. 解题思路:记忆化搜索,但是这里要四维的,因为要记录方向,为了防止走回头的路,并且取了几个负数也要记录.然后就是dfs了.状态转移方程:dp[x][y][d][k] = dp[x + dir[i][0]][y + dir[i][1]][i][k1] + G[x][