查找所有n位二进制数,r相邻数字为1

时间:2012-05-09 04:55:54

标签: algorithm math binary

让我举个例子来解释一下。如果n = 4且r = 2,则表示所有4位二进制数,使得两个相邻的数字可以是1.所以答案是0011 0110 1011 1100 1101

4 个答案:

答案 0 :(得分:3)

  

Q值。我无法弄清楚模式或算法。

提示:11可以从位置0,1或2开始。在任一侧,数字必须为零,因此唯一的“空闲”数字位于剩余位置,并且可以循环显示所有可能的值。

例如,如果有n = 10位且您正在寻找r = 3个相邻的数字,那么模式是

x01110y   

其中 x y 可循环显示剩余五个空闲数字的所有可能后缀和前缀。注意,在两侧,前导零和尾随零被删除,在 x0111 1110y 中留下六个空闲数字。

以下是使用Python的示例:

from itertools import product

def gen(n, r):
    'Generate all n-length sequences with r fixed adjacent ones'
    result = set()

    fixed = tuple([1] * r + [0])
    for suffix in product([0,1], repeat=n-r-1):
        result.add(fixed + suffix)

    fixed = tuple([0] + [1] * r + [0])
    rem = n - r - 2
    for leadsize in range(1, rem):
        for digits in product([0,1], repeat=rem):
            result.add(digits[:leadsize] + fixed + digits[leadsize:])

    fixed = tuple([0] + [1] * r)
    for prefix in product([0,1], repeat=n-r-1):
        result.add(prefix + fixed)

    return sorted(result)

答案 1 :(得分:1)

我将从简化问题开始。一旦找到了最简单案例的解决方案,请对其进行概括,然后尝试对其进行优化。

首先设计一种算法,找出给定数字是否与's'相邻。一旦你拥有它,蛮力的方式是用'n'数字遍历所有数字,用你刚刚开发的算法检查每个数字。

现在,您可以寻找优化它。例如:如果您知道'r'是偶数还是奇数,您可以减少要查看的数字集。 KNR给出的计数1算法是设定位数的顺序。因此,您排除了一半的案例,其复杂性较低,然后是实际的逐位比较。也许有一种更好的方法可以减少这种情况。

答案 2 :(得分:1)

非常简单的递归解决方案的有趣问题。 Delphi的。

  procedure GenerateNLengthWithROnesTogether(s: string;
    N, R, Len, OnesInRow: Integer; HasPatternAlready: Boolean);
  begin
    if Len = N then
      Output(s)
    else
    begin
      HasPatternAlready := HasPatternAlready or (OnesInRow >= R);
      if HasPatternAlready or (N - Len > R) //there is chance to make pattern}
       then
        GenerateNLengthWithROnesTogether('0' + s, N, R, Len + 1, 0, HasPatternAlready);
      if (not HasPatternAlready) or (OnesInRow < R - 1) //only one pattern allowed
      then
        GenerateNLengthWithROnesTogether('1' + s, N, R, Len + 1, OnesInRow + 1, HasPatternAlready);
    end;
  end;

begin
  GenerateNLengthWithROnesTogether('', 5, 2, 0, 0, False);
end;

program output:
N=5,R=2
11000  01100 11010  00110
10110  11001 01101  00011
10011  01011

N=7, R=3
1110000 0111000 1110100 0011100
1011100 1110010 0111010 1110110
0001110 1001110 0101110 1101110
1110001 0111001 1110101 0011101
1011101 1110011 0111011 0000111
1000111 0100111 1100111 0010111
1010111 0110111 

答案 3 :(得分:0)

正如我在上面的评论中所述,我仍然不清楚输出集的完全限制。但是,下面的算法可以改进以涵盖您的最终案例。

在我描述算法之前,有一个观察结果:让 S 重复1m次, D 为集合我们可以用来生成有效输出的所有可能后缀。因此,位串S0D0(S后跟0位,后跟位串 D 后跟0位)是算法的有效输出。此外,所有字符串ror(S0D0, k)0<=k<=n-m都是有效输出(ror向右旋转函数,其中右侧消失的位从左侧进入) 。这些将生成位字符串S0D00D0S。除了这些旋转之外,解S0D11D0S是有效的位字符串,可由该对生成( S D )。

因此,该算法只是枚举所有有效的 D 位字符串,并为每个( S D )对生成上述集合。如果在 D 部分中允许超过m 1,则它是简单的位枚举。如果不是,则它是递归定义,其中D是具有n'=n-(m+2)m' is each of {m, m-1, ..., 1}的相同算法的输出集。

当然,这个算法会产生一些重复。我能想到的情况是ror(S0D0,k)与其中一种模式S0E0S0E11E0S匹配的情况。对于第一种情况,您可以停止为较大的k值生成更多输出。 D=E生成器会处理这些。你也可以简单地放弃其他两种情况,但你需要继续旋转。


我知道有一个答案,但我想看到算法在起作用,所以我实现了一个原始版本。事实证明,边缘情况比我意识到的要多。我没有为family()函数的最后两个结果添加重复检查,这会导致11011等输出重复,但大多数都被删除了。

def ror(str, n):
    return str[-n:]+str[:-n]

def family(s, d, r):
    root = s + '0' + d + '0'
    yield root  # root is always a solution
    for i in range(1, len(d)+3):
        sol=ror(root, i)
        if sol[:r]==s and sol[r]=='0' and sol[-1]=='0':
            break
        yield sol
    if d[-r:]!=s: # Make sure output is valid
        yield s + '0' + d + '1'
    if d[:r]!=s:  # Make sure output is valid (todo: duplicate check)
        yield '1' + d + '0' + s

def generate(n, r):
    s="1"*r
    if r==0: # no 1's allowed
        yield '0'*n
    elif n==r: # only one combination
        yield s
    elif n==r+1: # two cases. Cannot use family() for this
        yield s+'0'
        yield '0'+s
    else:
        # generate all sub-problem outputs
        for rr in range(r+1):
            if n-r-2>=rr:
                for d in generate(n-r-2, rr):
                    for sol in family(s, d, r):
                        yield sol

您可以将其用作[s for s in generate(6,2)],也可以将其用作

循环
for s in generate(6,3):
    print(s)
相关问题