动态规划+位掩码
Dynamic Programming +Bit-Masks
我最近学习了竞争性编程的位操作概念,所以我对这个概念很陌生,我也阅读了很多关于位掩码的教程+ 动态编程 上 Hackerearth、CodeChef 等等。
我还在 Codechef 上解决了几个问题,包括这个 problem
在我回答了一些问题之后,我对位掩码有一些疑问。
我解决的问题主要集中在操纵 子集 但我想知道我如何使用位掩码处理 permutations ,即什么时候我必须在需要设置掩码中所有位的状态下工作。
例如:如果我们必须找到可以通过排列给定数字 A 的所有数字组成的数字的数量,这些数字可以被给定数字 B 整除,其中 (A ,B<= 10**6) 如何这可以用位掩码来完成吗?(我希望这可以用位掩码+dp来完成)
如果 A=514,且 B=2
该问题期望答案为
514
154
它们都可以被 2 整除。
所以答案是2。
据我了解:514 和 154 代表相同的掩码 111,其中所有位都是 set 那么我如何在掩码所在的位置使用位掩码两个或更多答案相同!(我希望你明白这一点)。
而且由于我们可以有那么多的数字排列,所以不可能为 n!*n 的值分配价值 n!*n 的内存,所以如何使用我们只需要 (2*) 的位掩码来解决这个问题*n)*n space (如果我没记错的话)。
那么如何迭代地解决上述问题呢? /或我可能理解的任何 DP 状态方程,我无法理解我读过的一些类似问题的递归方法。
我也想过类似的问题TSHIRTS,但我无法理解递归背后的逻辑。
你实际上不需要 DP,但你可以很好地使用位操作 :) 因为 A <= 10^6 这意味着 A 最多有 7 个数字;所以你只需要检查7! = 5040 个州。
const int A = 514;
const int B = 2;
vector <int> v; //contains digits of A (e.g. 5, 1, 4) this can be done before the recursive function in a while loop.
int rec(int mask, int current_number){
if(mask == (1 << v.size()) - 1){ //no digit left to pick
if(current_number % B == 0) return 1;
else return 0;
}
int ret = 0;
for(int i = 0; i < v.size(); i++){
if(mask & (1 << i)) continue; //this is already picked
ret += rec(mask | (1 << i), current_number * 10 + v[i]);
}
return ret;
}
注意我这里没有使用DP的原因是即使掩码相同,当前数字也可能不同;所以你实际上不能说这种情况已经重复了。除非你记住掩码 AND current_number 这需要更多 space.
我最近学习了竞争性编程的位操作概念,所以我对这个概念很陌生,我也阅读了很多关于位掩码的教程+ 动态编程 上 Hackerearth、CodeChef 等等。
我还在 Codechef 上解决了几个问题,包括这个 problem 在我回答了一些问题之后,我对位掩码有一些疑问。
我解决的问题主要集中在操纵 子集 但我想知道我如何使用位掩码处理 permutations ,即什么时候我必须在需要设置掩码中所有位的状态下工作。
例如:如果我们必须找到可以通过排列给定数字 A 的所有数字组成的数字的数量,这些数字可以被给定数字 B 整除,其中 (A ,B<= 10**6) 如何这可以用位掩码来完成吗?(我希望这可以用位掩码+dp来完成)
如果 A=514,且 B=2 该问题期望答案为
514
154
它们都可以被 2 整除。
所以答案是2。 据我了解:514 和 154 代表相同的掩码 111,其中所有位都是 set 那么我如何在掩码所在的位置使用位掩码两个或更多答案相同!(我希望你明白这一点)。
而且由于我们可以有那么多的数字排列,所以不可能为 n!*n 的值分配价值 n!*n 的内存,所以如何使用我们只需要 (2*) 的位掩码来解决这个问题*n)*n space (如果我没记错的话)。
那么如何迭代地解决上述问题呢? /或我可能理解的任何 DP 状态方程,我无法理解我读过的一些类似问题的递归方法。
我也想过类似的问题TSHIRTS,但我无法理解递归背后的逻辑。
你实际上不需要 DP,但你可以很好地使用位操作 :) 因为 A <= 10^6 这意味着 A 最多有 7 个数字;所以你只需要检查7! = 5040 个州。
const int A = 514;
const int B = 2;
vector <int> v; //contains digits of A (e.g. 5, 1, 4) this can be done before the recursive function in a while loop.
int rec(int mask, int current_number){
if(mask == (1 << v.size()) - 1){ //no digit left to pick
if(current_number % B == 0) return 1;
else return 0;
}
int ret = 0;
for(int i = 0; i < v.size(); i++){
if(mask & (1 << i)) continue; //this is already picked
ret += rec(mask | (1 << i), current_number * 10 + v[i]);
}
return ret;
}
注意我这里没有使用DP的原因是即使掩码相同,当前数字也可能不同;所以你实际上不能说这种情况已经重复了。除非你记住掩码 AND current_number 这需要更多 space.