UVA1252 20个问题 Twenty Questions
一、前言
本题是一道状压 DP,由于本人状压 DP学的不好,故写下这篇题解加深理解。本文将介绍位运算,状压 DP,以及做题思路。
二、位运算
-
位运算的一个重要作用就是表示一个集合,常见于状压 DP。
-
一个数的二进制可以看作是一个集合(
0 表示在这个集合中,1 表示不在这个集合中)。而这时的位运算可以看做是对集合的操作。
| 操作 | 集合表示 | 位运算语句 |
|---|---|---|
| 交集 | a & b |
|
| 并集 | a | b |
|
| 补集 | ~ a (全集为二进制都是一) |
|
| 差集 | a & (-b) |
|
| 对称差 | a ^ b |
三、题意
有
四、思路
(1) 审题
首先看到二进制串就很快能想到状压 DP,再一看
适合状态压缩的情况:
-
状态复杂,难以表达。
-
但是状态数量少,且决策较少(最好就只有两个,符合二进制)
(2) 状态
由于我们在询问过一个特征值之后就不需要再询问一遍,因此我们可以设一个集合
(3) 转移
我们假设下一次提问的对象是特征
取
(4) 实现
具体实现用记忆化搜索更优,因为这里我们难以确定递推顺序,而记忆化搜索不需要考虑顺序。
五、状压 DP
接下来我会举一些本题的代码为例子来阐述状压 DP 的具体实现。
(s&(1<<k))==0;
s|(1<<k);
a | b是取两者的并集,一般表示把两个集合相加,在这里表示在s 集合中加入k 元素。
for(int i = s; i; i = (i-1)&s)
- 遍历
s 集合。
六、后记
-
参考文献:
oi - wiki、 《算法竞赛入门经典》