计算案例数的有效位

时间:2018-03-08 17:25:22

标签: dynamic-programming combinatorics bitmask number-theory

我想知道计算案件数量的比特方式。

SITUAITION

检查n / 2的整个可能的n / 2个案例。

MY APPROACH

bool possible(int state)

它是计算' 1'的功能。在该州。如果cnt等于n / 2则返回true,或返回false。

inline bool possible(int state){
    int cnt=0;
    for(int t=1;;t*=2){
        if(t==(1<<n)) break;
        if(cnt>n/2) break;
        if((t&state)==t) ++cnt;
    }

    if(cnt==n/2) return true;
    else return false;
}

void query()

它搜索所有可能的状态。

inline void query(){
    int tar=n/2;
    int ss=(1<<tar)-1;
    int ee=(1<<n)-1;
    for(int i=ss;i<=ee;++i){
        if(possible(i)) process(i);
    }
}

我想使用位掩码来解决n的所有n / 2个案例。 但我认为query()函数无效,因为它搜索整个案例。有没有有效的方法来解决这个问题?

BIT-ON的含义

例如,如果n = 4,那么我们必须对两个索引进行bit-on, 在基于0的索引中,

0001 [失败]

0010 [失败]

0011 [0,1 bit-on的指数]

0100 [失败]

0101 [指数为0.2位开启]

0110 [1,2位开启指数]

0111 [失败]

1000 [失败]

1001 [0.3位开启指数]

1010 [1,3位开启指数]

1011 [失败]

1100 [2,3位开启指数]

1101 [失败]

1110 [失败]

1111 [失败]

显然,4C2 =选择6个案例,所以状态,

将搜索

[0011,0101,0110,1001,1010,1100]

1 个答案:

答案 0 :(得分:1)

问题可以递归解决

  • 首先选择最左边的位置&#34; 1&#34;
  • 然后递归调用该函数以放置剩余的&#34; 1&#34; s
  • 当没有&#34; 1&#34; s留下
  • 时,递归结束

这意味着您需要定义一个更通用的函数,以n位数生成k&#34; 1&#34;

避免返回和处理子结果的一个方便的技巧是向下传递累加器。您可以在递归中深入调用process()函数。

python中的示例代码。应该很容易翻译成C.

def process(i):
    '''prints decimal and binary representation of i'''
    print(i, bin(i))

def helper1(length, ones, acc):
    if ones == 0:
        process(acc)
    else:
        for i in range(ones-1, length):   # iterates from ones-1 to length-1
            helper1(i, ones-1, acc | (1<<i))

def solution1(n):
    helper1(n, n >> 1, 0)

在现代CPU上,这应该运行得很好。它可以被改进&#34;虽然使用位掩码而不是索引作为参数。但是,代码变得更难理解。

def helper2(first_mask, last_mask, acc):
    if last_mask == 0:
        process(acc)
    else:
        mask = last_mask
        while mask <= first_mask:
            helper2(mask >> 1, last_mask >> 1, acc | mask)
            mask = mask << 1

def solution2(n):
    helper2(1 << (n-1), 1 << (n//2 -1), 0)
  • first_mask代表最左边的位置,其中&#34; 1&#34;可插入
  • last_mask代表&#34; 1&#34;可以插入(这样剩余的空间仍然有足够的空间&#34; 1&#34; s)。它还可以作为剩余&#34; 1&#34; s的计数器。

位变换-劈

我刚刚发现你也可以在没有递归的情况下解决问题:

从最小的数字开始,在循环中找到下一个更大的数字。 要找到更多的数字,您需要移动&#34; 1&#34;到下一个&#34; 0&#34;的位置向左移动,然后移动新&#34; 1&#34;右边的所有&#34; 1&#34;非常正确。

虽然听起来很复杂但可以使用bit-twiddling-hacks快速完成。

def helper3(total, ones):
    if ones == 0:
        process(0)
        return
    i = (1 << ones) - 1
    while i < (1 << total):
        process(i)
        last_one_mask = (((i - 1) ^ i)  >> 1) + 1
        temp = i + last_one_mask
        i = temp | (((temp ^ i) // last_one_mask) >> 2)

def solution3(n):
    helper3(n, n >> 1)

如果您的语言具有恒定宽度整数,则在计算temp时可能会出现溢出。为了避免不良行为,您必须在temp<i

中止循环