状态压缩是指使用计算机二进制位来存储状态,一般用法是将二进制串当做一个集合,bit位代表集合中的元素,bit位取值表示元素是否在集合中。n位二进制串可以描述2^n种集合(状态),因此对于n的取值是相当严格的。状态压缩DP中需要使用各种位运算来描述状态转换。所以需要对位运算的使用有一定的了解,下面是一些巧妙的运用。

  1. 把一个数字x最靠右的第一个1去掉 : x = x & (x-1)
  2. 判断数字x中是否存在相邻的1 : x & (x >> 1)

需要注意,位运算的优先级通常比较低,如果不熟悉这些优先级,建议多使用括号避免出错。


UVa10817-Headmaster's Headache是一道典型的状态压缩DP。

题意:
某校有某个教师和n个求职者,需讲授s个课程(1 ≤ s ≤ 8, 1 ≤ m ≤ 20, 1 ≤ n ≤ 100)。已知每人工资c(10000 ≤ c ≤ 50000)和能教的课程集合,要求支付最少的工资使得每门课至少有两个教师能教。在职教师不能辞退。

分析:
本题使用状态压缩显然应该讲课程作为要压缩的状态,考虑每门课程至少有两个教师教。状态定义如下:

  1. 16位长二进制串代表状态,bit位代表课程,其中低八位代表有一位老师教该课程,高八位代表有两个老师教该课程。
  2. dp[n][s]代表考虑前n个老师的情况下,维护一个状态最少需要多少开销。
  3. 每个老师维护一个状态,代表其能教导的课程。

此时状态转移方程如下:

int changeState(int from, int by)
{int first = (~from) & by;                       // 第一个上这门课的老师int second = from & by;                         // 第二个上这门课的老师int to = (from | first | (second << 8));        // 增加这个老师后的状态return to;
}

代码:

// 状态压缩DP
#include <iostream>
#include <sstream>
#include <cstdio>
#include <bitset>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_S = 8;
const int MAX_N = 100;
const int MAX_STATE = (1 << 16) - 1;
const int INF_ = 0x3f3f3f3f;int begin_state;                                    // 初始状态
int begin_cost;                                     // 初始开销
int states[MAX_N+1];                                // 应聘者状态
int costs[MAX_N+1];                                 // 应聘者工资
int dp[MAX_N+1][MAX_STATE+1];                       // 考虑前i个应聘者时,维护每个状态所需最小开销int changeState(int from, int by)
{int first = (~from) & by;                       // 第一个上这门课的老师int second = from & by;                         // 第二个上这门课的老师int to = (from | first | (second << 8));        // 增加这个老师后的状态return to;
}void input(int s, int m, int n)
{begin_state = ((1 << 16) - 1) - ((1 << (s+8))-1) + ((1 << 8) - 1) - ((1 << s) - 1);begin_cost = 0;for (int i = 0; i < m; i++){string str;int cost, lesson;cin >> cost;begin_cost += cost;getchar();getline(cin, str);stringstream ss(str);while (ss >> lesson){lesson--;begin_state = changeState(begin_state, (1 << lesson));}}for (int i = 1; i <= n; i++){string str;int state = 0, lesson;cin >> costs[i];getchar();getline(cin, str);stringstream ss(str);while (ss >> lesson){lesson--;state = changeState(state, (1 << lesson));}states[i] = state;}
}int solve(int s, int m, int n)
{memset(dp, INF_, sizeof(dp));dp[0][begin_state] = begin_cost;for (int i = 1; i <= n; i++){for (int j = 0; j <= MAX_STATE; j++){int to_state = changeState(j, states[i]);dp[i][j] = min(dp[i][j], dp[i-1][j]);                           // 不增加这个老师dp[i][to_state] = min(dp[i][to_state], dp[i-1][j]+costs[i]);    // 增加这个老师}}return dp[n][MAX_STATE];
}int main()
{int s, m, n;while (true){cin >> s >> m >> n;if (s == 0) break;input(s, m, n);cout << solve(s, m, n) << endl;}
}

状态压缩DP UVa10817-Headmaster's Headache相关推荐

  1. 0x56. 动态规划 - 状态压缩DP(习题详解 × 7)

    目录 Problem A. 最短Hamilton路径 ProblemB. 蒙德里安的梦想 Problem C. Corn Fields Problem D. 小国王 Problem E. 炮兵阵地 P ...

  2. POJ 2411 Mondriaan‘s Dream(最清楚好懂的状压DP讲解)(连通性状态压缩DP)

    poj 2411 Mondriaan's Dream(最清晰的状压DP解析) 闫氏DP大法好 我们这里是一列一列地来,因为是一个棋盘性的状态压缩DP,从哪个方向都一样 摆放的小方格总方案数 等价于 横 ...

  3. BZOJ1688|二进制枚举子集| 状态压缩DP

    Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) diseases (numbered 1..D) ...

  4. hdu1074 状态压缩dp+记录方案

    题意:       给你一些作业,每个作业有自己的结束时间和花费时间,如果超过结束时间完成,一天扣一分,问你把n个作业完成最少的扣分,要求输出方案. 思路:       状态压缩dp,记录方案数的地方 ...

  5. FZU-2218 Simple String Problem(状态压缩DP)

    原题地址: 题意: 给你一个串和两个整数n和k,n表示串的长度,k表示串只有前k个小写字母,问你两个不含相同元素的连续子串的长度的最大乘积. 思路: 状态压缩DP最多16位,第i位的状态表示第i位字母 ...

  6. 《算法竞赛进阶指南》打卡-基本算法-AcWing 91. 最短Hamilton路径:位运算、状态压缩dp、dp

    文章目录 题目解答 题目链接 题目解答 分析: 状态压缩dp是用二进制数来表示状态. 数据范围n = 20, 那么状态总量就是2202^{20}220个状态. 可以按照以下思路去思考: 哪些点被用过 ...

  7. 状态压缩DP AcWing算法提高课 (详解)

    基础课的状态压缩点这里 基础课中 蒙德里安的梦想 属于 棋盘式状态压缩dp,最短Hamilton路径 属于 集合状态压缩dp 1064. 小国王(棋盘式/基于连通性) 这种棋盘放置类问题,在没有事先知 ...

  8. hdu 5067(状态压缩dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5067 解题思路:这道题开始想复杂了,想用bfs去求出最短距离,其实没必要,因为题目中没有阻碍关系,所以 ...

  9. hdu 5418(状态压缩dp+Floyd)

    点击打开链接 解题思路:这道题目和TSP问题很相似,唯一不同的是同一个点可以重复走几次.... 这道题目只有16个顶点,所以很容易想到状态压缩dp,dp[i][j]表示到达顶点i时的状态为j的最小花费 ...

最新文章

  1. linux chown命令 改变文件拥有者
  2. opencv上gpu版surf特征点与orb特征点提取及匹配实例
  3. 课时 18-Kubernetes 调度和资源管理(子誉)
  4. mysql存储过程大于小于_mysql5.0存储过程操作符知识_函数方法[Mysql学习]
  5. 四十九、微信小程序开发页面样式WXSS和页面交互JS
  6. Python中读取打开文件的各种模式以及代表含义
  7. NOIP 2006 T2 金明的预算方案
  8. 利用nginx的301重定向到另外服务器
  9. WebGL(四)—— 第一个WEBGL程序
  10. 美赛整理之带参数的常微分方程拟合问题研究
  11. python turtle画小狗_python-turtle-画雪花
  12. ubuntu下tftp服务器环境搭建
  13. 音频编解码G729 PCM
  14. Thymeleaf模板引擎使用详解
  15. 基于Elasticsearch 实现站内全文搜索
  16. python 因子分析 权重计算_Python与量化多因子——因子权重优化
  17. The client-side rendered virtual DOM tree is not matching server-rendered content. 问题
  18. 后端开发工程师技术导图
  19. 扔掉你 WINDOWS 中的盗版软件吧
  20. python困境_Python笔记-囚徒困境及记录困境中的选择

热门文章

  1. Nacos-配置集中管理
  2. 强大合作伙伴生态系统助力 Denodo 在大中华区不断发展壮大
  3. 第九回(二):任侠厨子轻解厄围 夜半蹴鞠为泄忿闷[林大帅作品集]
  4. 09.12.15 转:什么是工作?我终于明白了
  5. 一.二.管理和信息化软件的关系
  6. Java SE核心API(2) —— 正则表达式、Object、包装类
  7. discuzx update sitekey.php,Discuz如何清除应用中心密码附加工具
  8. 用SpringBoot简单实现登录注册功能
  9. IOException: No such file or directory 问题解决
  10. 搭建speedtest server