[HDOJ - 5208] Where is Bob 【DFS+按位贪心】
题目链接:HDOJ - 5208
题目分析
使用按位贪心的思想,即从高位向低位枚举,尽量使这一位的答案为 1 。
我们使用 DFS ,每次就是对于 [l1, r1] [l2, r2] x 进行处理,其中,x 是当前处理的最高位的权值,即 2^i 。
如果 A 和 B 两人的区间的最高位都确定了,那就记录这一位的答案,直接处理下一位。
如果 A 可以取 0/1 ,而 B 已经确定了,那么 A 就一定要取与 B 相反的那个。
如果 A 和 B 都能取 0/1 ,那么我们就要分支进行 DFS ,一种是 A-1 B-1 ,另一种是 A-0 B-0 ,然后取这两种情况答案的较大值。
然而剪枝是十分有效的,必须加上“如果 B 的区间完全包含了 A 的区间,直接返回 0”。不加这句就会 TLE 。(这样能将大部分分支剪掉?)
另外,如果当前的区间是 [l, r] l < x && r >= x
那么最高位就可以选 0 也可以选 1。
如果决策选 0 ,那么到下一位的区间就变为 [l, x - 1] 。
如果决策选 1 ,那么到下一位的区间就变为 [x, r - x]。
代码
#include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; inline int gmax(int a, int b) {return a > b ? a : b;} int Ans, l, r, ll, rr, T; int Solve(int l, int r, int ll, int rr, int x) { if (x == 0 || (ll <= l && rr >= r)) return 0; int v, vv; if (r < x) v = 0; else if (l >= x) v = 1; else v = 2; if (rr < x) vv = 0; else if (ll >= x) vv = 1; else vv = 2; if (v == 0) { if (vv == 0) // A-0 B-0 return Solve(l, r, ll, rr, x >> 1); else if (vv == 1) // A-0 B-1 return x + Solve(l, r, ll - x, rr - x, x >> 1); else // A-0 B-0-1 return Solve(l, r, ll, x - 1, x >> 1); } else if (v == 1) { if (vv == 0) // A-1 B-0 return x + Solve(l - x, r - x, ll, rr, x >> 1); else if (vv == 1) // A-1 B-1 return Solve(l - x, r - x, ll - x, rr - x, x >> 1); else // A-1 B-0-1 return Solve(l - x, r - x, 0, rr - x, x >> 1); } else { if (vv == 0) // A-0-1 B-0 return x + Solve(0, r - x, ll, rr, x >> 1); else if (vv == 1) // A-0-1 B-1 return x + Solve(l, x - 1, ll - x, rr - x, x >> 1); else // A-0-1 B-0-1 return gmax(Solve(l, x - 1, ll, x - 1, x >> 1), Solve(0, r - x, 0, rr - x, x >> 1)); } } int main() { scanf("%d", &T); for (int Case = 1; Case <= T; ++Case) { scanf("%d%d%d%d", &l, &r, &ll, &rr); Ans = Solve(l, r, ll, rr, 1 << 30); printf("Case #%d: %d\n", Case, Ans); } return 0; }