让我举个例子来解释一下。如果n = 4且r = 2,则表示所有4位二进制数,使得两个相邻的数字可以是1.所以答案是0011 0110 1011 1100 1101
答案 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 重复1
次m
次, D 为集合我们可以用来生成有效输出的所有可能后缀。因此,位串S0D0
(S后跟0位,后跟位串 D 后跟0位)是算法的有效输出。此外,所有字符串ror(S0D0, k)
,0<=k<=n-m
都是有效输出(ror
是向右旋转函数,其中右侧消失的位从左侧进入) 。这些将生成位字符串S0D0
到0D0S
。除了这些旋转之外,解S0D1
和1D0S
是有效的位字符串,可由该对生成( S , D )。
因此,该算法只是枚举所有有效的 D 位字符串,并为每个( S , D )对生成上述集合。如果在 D 部分中允许超过m
1,则它是简单的位枚举。如果不是,则它是递归定义,其中D是具有n'=n-(m+2)
和m' is each of {m, m-1, ..., 1}
的相同算法的输出集。
当然,这个算法会产生一些重复。我能想到的情况是ror(S0D0,k)
与其中一种模式S0E0
,S0E1
或1E0S
匹配的情况。对于第一种情况,您可以停止为较大的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)