[UVA 10817]Headmaster's Headache[状压DP]
2015-08-22 23:25
211 查看
题目链接:[UVA 10817]Headmaster's Headache[状压DP]
题意分析:
校长需要s门课,每门至少有两名老师来教,所以他现在想要招老师啦。当然,校长手头本来就有m个老师,每个老师都教着一个或多个课程,这些老师是不能解雇的,必须用。然后现在又n个老师来应聘,每个都有价格和他们能教的课程,校长希望花最少的钱达到他的目标,问:最少多少钱呢?
解题思路:
嘛!s <= 8,赤裸裸的暗示(?)。我们可以设置两个集合,s1对应还需要一个老师教的科目,s2对应已经足够老师教的科目,状态设为dp[i][s1][s2]:代表到第i个老师为止,校长最少需要花多少钱达到目标。当i < m 时,我们必须选择,状态只能更新为添加老师,当i >= m时, 就可以更新为选或不选老师两种状态。
个人感受:
第一次写这道题,不会,然后补题,看别人代码。昨天又一次碰到,除了知道是状压外,依稀只记得集合存科目这种事。今天重新做一遍,看了看状态,自己写了转移,感触颇多啊。之前看刘汝佳代码,他设置了三个集合,整个运算符用得极其魔幻(?),当时理解了半天。这次自己写的转移,只用到了其中的两个集合,发现第一个完全可以省略嘛XD,然后两行就完成了转移XD。重做出奇迹啊。。。。
具体代码如下:
题意分析:
校长需要s门课,每门至少有两名老师来教,所以他现在想要招老师啦。当然,校长手头本来就有m个老师,每个老师都教着一个或多个课程,这些老师是不能解雇的,必须用。然后现在又n个老师来应聘,每个都有价格和他们能教的课程,校长希望花最少的钱达到他的目标,问:最少多少钱呢?
解题思路:
嘛!s <= 8,赤裸裸的暗示(?)。我们可以设置两个集合,s1对应还需要一个老师教的科目,s2对应已经足够老师教的科目,状态设为dp[i][s1][s2]:代表到第i个老师为止,校长最少需要花多少钱达到目标。当i < m 时,我们必须选择,状态只能更新为添加老师,当i >= m时, 就可以更新为选或不选老师两种状态。
个人感受:
第一次写这道题,不会,然后补题,看别人代码。昨天又一次碰到,除了知道是状压外,依稀只记得集合存科目这种事。今天重新做一遍,看了看状态,自己写了转移,感触颇多啊。之前看刘汝佳代码,他设置了三个集合,整个运算符用得极其魔幻(?),当时理解了半天。这次自己写的转移,只用到了其中的两个集合,发现第一个完全可以省略嘛XD,然后两行就完成了转移XD。重做出奇迹啊。。。。
具体代码如下:
#include<iostream> #include<cstring> #include<string> #include<sstream> using namespace std; const int INF = 0x7f7f7f7f, MAXN = 131; int s, m, n, teach[MAXN], cost[MAXN], dp[MAXN][1 << 8][1 << 8]; int DP(int i, int s1, int s2) { if (i == m + n) return s2 == (1<<s) - 1 ? 0 : INF; //每个科目都至少两个老师了,那么就不需要再花钱了 int &ret = dp[i][s1][s2]; if (ret >= 0) return ret; ret = INF; if (i >= m) ret = DP(i + 1, s1, s2); //不选 s2 |= (s1 & teach[i]); //老师能教,并且差一个老师,那么一并运算,剩下的就是满足条件的科目 s1 |= teach[i]; //或上去,没人教的科目肯定变成差一个人教 ret = min(ret, cost[i] + DP(i + 1, s1, s2)); //选 return ret; } int main() { while (cin >> s >> m >> n && s) { cin.get(); string ss; int x; for (int i = 0; i < m + n; ++i) { getline(cin, ss); stringstream sss(ss); sss >> cost[i]; teach[i] = 0; while(sss >> x) { teach[i] |= 1 << (x - 1); } } memset(dp, -1, sizeof dp); //for (int i = 0; i < m + n; ++i) cout << cost[i] << ':' << teach[i] << endl; cout << DP(0, 0, 0) << '\n'; } return 0; }
相关文章推荐
- 编写高质量代码改善C#程序的157个建议——建议120:为程序集指定强名称
- 生成伪随机整数
- android自定义view错误收集
- MFC数据类型(data types)
- win7_oracle11g_64位连接32位PLSQL_Developer
- SPOJ - NSUBSTR Substrings 后缀自动机
- 数据结构-什么是算法?
- 野人学Android基础篇之HelloWorld程序第一课--程序目录介绍
- 剑指off-求两个整数的和
- C语言字符串、指针和内存问题总结
- 我是菜鸟:深入java容器内部
- 跟踪 Ring3 - Ring0 的执行流程
- 介绍两个很好用的jquery插件
- TextView跑马灯效果
- 【传递正能量】献给默默追梦的人
- hdu 3605 二分图多重匹配
- 洛谷1309 瑞士轮 解题报告
- NSFileManager
- 新手应该掌握的Linux命令
- 在远程ssh登陆和本地登陆时显示日期和主机名