按位操作符与背包问题的遍历

来源:互联网 发布:网络骑士是哪里人 编辑:程序博客网 时间:2024/06/06 16:39

按位操作符与背包问题的遍历

今天brute force 作业的案例和问题都十分有趣,而遍历的过程更能加深对按位操作符作用的理解。

Example

习题之前给的出的例子是单个背包组合遍历

# generate all combinations of N itemsdef powerSet(items):    N = len(items)    # enumerate the 2**N possible combinations    for i in range(2**N):        combo = []        for j in range(N):            # test bit jth of integer i            # ">>" is one bit right move in binary, equals divde 2**j            # mod used to present last digit of the binary            # check jth digit of integer i, if 1 take it            if (i >> j) % 2 == 1:                combo.append(items[j])        yield combo

解释

N个物品往背包里放,对于每个来说都可以放或者不放,所以总共有2**N种情况。而用N位的二进制数字恰好能和每一种情况一一对应——放入背包为1, 不放背包为0。

要求列出的是所有放入的组合,所以只需考虑任何为1(也就是放入)的情况。所以对于2**N个种放法中每一种(循环i),都需要逐个检查(循环j),而移动 j 次的是左数 (N - j) 位数,也就是左数 (N - j) 个物品,也就是 item[N - j - 1],物品仅仅代号不同所以可用 N 代替 N - j - 1 即可

assignment

作业两个背包遍历

def yieldAllCombos(items):    """        Generates all combinations of N items into two bags, whereby each         item is in one or zero bags.        Yields a tuple, (bag1, bag2), where each bag is represented as a list         of which item(s) are in each bag.    """    # Your code here    N = len(items)    # any given item have 3 condition: bag1, bag2, not taken    # so enumerate 3**N possible combinations    for i in range(3**N):        # fresh start        bag_1, bag_2 = [], []        for j in range(N):            # resembling "Trinary" digits, check jth item from the right, if 1 put in bag_1            if (i // (3**j)) % 3 == 1:                bag_1.append(items[j])            # resembling "Trinary" digits, check jth item from the right, if 2 put in bag_2            if (i // (3**j)) % 3 == 2:                bag_2.append(items[j])        yield (bag_1, bag_2)

任意物品有3种状态:背包1,背包2,未放入,共有3**N种情况,假如有“三进制”的话则恰好可以与每种情况一一对应,因此在 j 循环中,实际是创造了三进制来表示 i 循环中每一种情况,再利用整数除法将第 N - j 位向右移动 j 位检查所属位置,同样用 generator 即可。

原创粉丝点击