我要解决的是一个难题。在
考虑一个长度为n的二进制向量,它最初都是零。你选择一个向量并将其设置为1。现在,一个进程开始设置从任何1位到$1$的最大距离的位(如果有多个位,则任意选择最远的位)。这种情况会反复发生,因为规则是两个1位不能相邻。当没有足够的空间放置1位时,它终止。目标是放置初始的1位,以便尽可能多的位在终止时被设置为1。在
假设n=2。那么无论我们在哪里设置位,我们最终只设置了一个位。在
对于n=3,如果我们设置第一个位,最后得到101。但是如果我们设置中间位,我们得到010,这不是最优的。在
对于n=4,无论我们设置了哪一个位,我们都会得到两组。在
对于n=5,设置第一个值得到10101,最后设置三个位。在
对于n=7,我们需要设置第三个位,以获得1010101。在
我写了一些代码来寻找最佳值,但是它不能很好地扩展到大n。我的代码在n=1000左右开始变慢,但是我想用n大约100万来解决这个问题。在
#!/usr/bin/python
from __future__ import division
from math import *
def findloc(v):
count = 0
maxcount = 0
id = -1
for i in xrange(n):
if (v[i] == 0):
count += 1
if (v[i] == 1):
if (count > maxcount):
maxcount = count
id = i
count = 0
#Deal with vector ending in 0s
if (2*count >= maxcount and count >= v.index(1) and count >1):
return n-1
#Deal with vector starting in 0s
if (2*v.index(1) >= maxcount and v.index(1) > 1):
return 0
if (maxcount <=2):
return -1
return id-int(ceil(maxcount/2))
def addbits(v):
id = findloc(v)
if (id == -1):
return v
v[id] = 1
return addbits(v)
#Set vector length
n=21
max = 0
for i in xrange(n):
v = [0]*n
v[i] = 1
v = addbits(v)
score = sum([1 for j in xrange(n) if v[j] ==1])
# print i, sum([1 for j in xrange(n) if v[j] ==1]), v
if (score > max):
max = score
print max
最新答案(O(logn)复杂性)
如果我们相信templatetypedef和Aleksi Torhamo的猜想(update:在这篇文章的最后证明),存在一个封闭形式的解}中计算(或者{},如果我们假设对数和位移位是
count(n)
,可以在{O(1)
):Python:
C++:
^{pr2}$这段代码可以计算
n=100,000,000
(甚至在Python中是n=1e24
)的结果立即正确1。在我测试了
n
的不同值的代码(使用我的O(n)
解决方案作为标准,请参见下面的旧答案部分),它们似乎仍然正确。在这段代码依赖于templatetypedef和Aleksi Torhamo2的两个猜想。
有人想证明吗?=D(更新2:经验证)1我的意思是几乎立即
Aleksi Torhamo关于
f
函数的猜想已被n<=100,000,000
的经验证明旧答案(O(n)复杂性)
我可以使用Python2.7在1.358s(在我的iMac中)中返回
n=1,000,000
(结果是475712
)的计数。<>更新> eEM>:C++中的{{CD13}}为0.19s。=)这是我的想法,它实现了
O(n)
时间复杂性。在算法
{cd15}的定义
将
f(n)
定义为将在长度为n
的位向量上设置的位数,假设第一位和最后一位都被设置为(除了n=2
,其中只设置了第一位或最后一位)。因此我们知道f(n)
的一些值如下:请注意,这与我们正在寻找的值不同,因为初始位可能不在第一位或最后一位,正如
f(n)
计算的那样。例如,我们有f(7)=3
而不是4。在注意,这可以相当有效地计算(摊销}的所有值),使用递归关系:
O(n)
来计算f
到{对于
n>=5
,因为遵循规则的下一个位集将是中间位,除了n=1,2,3,4
。然后我们可以将位向量分成两部分,每个部分相互独立,这样我们就可以使用f( floor(n/2) ) + f( ceil(n/2) ) - 1
来计算比特集的数目,如下所示:我们在公式中使用
-1
,以排除中间位的双计数。在现在我们准备计算原问题的解。在
g(n,i)
的定义将}。在
g(n,i)
定义为将在长度为n
的位向量上设置的位数,遵循问题中的规则,其中初始位位于i
-位(基于1)。注意,通过对称,初始位可以是从第一位到第ceil(n/2)
-位的任何位置。对于这些情况,请注意,第一位将设置在第一位和初始位之间的任何位之前,最后一位也是如此。因此,第一分区和第二分区中的比特数分别为f(i)
和{{29>的值可以计算为:
在计算
f(n)
时遵循这个想法。在现在,计算最终结果是微不足道的。在
g(n)
的定义将
g(n)
定义为在原始问题中查找的计数。然后我们可以取所有可能的最大值i
,初始位的位置:Python代码:
复杂性分析
有趣的是,用上述方法计算
g(n)
的复杂度是多少?在我们首先要注意的是,我们迭代}。朴素的分析会导致}上使用了记忆,所以它比这个快得多,因为{}的每个值都是根据最多一次。因此,复杂性实际上是通过计算
n/2
的n/2
值,即初始位的位置。在每个迭代中,我们称之为f(i)
和{O(n * O(f(n)))
,但实际上我们在{f(n)
的所有值所需的时间而增加的,这将是O(n + f(n))
。在那么初始化
f(n)
的复杂性是什么呢?在我们可以假设在计算
f(n)
之前,我们先预计算f(n)
的每个值。注意,由于递归关系和记忆,生成f(n)
的整个值需要O(n)
时间。下一次调用f(n)
将花费O(1)
时间。在因此,总的复杂性是
O(n+n) = O(n)
,这可以从n=1,000,000
和n=10,000,000
的iMac中的运行时间证明:作为记忆化的一个副产品,
n
的较小值的计算在第一次调用大型n
之后会快得多,正如您在示例运行中看到的那样。而且,如果语言更适合于数字压缩,例如C++,则运行速度可能会大大加快。我希望这有帮助。=)
使用C++的代码,用于性能改进< /H2><> > C++中的结果约为68倍(用{{CD63}}测量):
<> C++中的代码:证据
注意,为了让这个答案(已经很长了)保持简单,我跳过了证明中的一些步骤
关于
f
值的Aleksi Torhamo猜想考虑到上述四种情况下的回归关系,可以很容易地证明:
k
k
k
k
因此通过归纳证明了这个猜想。在
templatetypedef在最佳位置的猜想
证明:
所以这个猜想被证明了。在
因此,为了打破我通常不公布算法的传统,我没有证据,我想我应该提一下,有一种算法似乎对50000+以内的数字是正确的,并且运行时间为O(logn)。这要归功于Sophia Westwood,我今天和他共事了大约三个小时。这一切都归功于她。从经验上看,它似乎运行得很好,而且比O(n)解决方案快得多。在
关于这个问题结构的一个观察是,如果n足够大(n≥5),那么如果你把1放在任何地方,问题就会分成两个子问题,一个在1的左边,一个在右边。虽然1可能会在不同的时间被放在不同的两半,但最终的布局是一样的,就像你把每一半分开求解,然后把它们组合在一起。在
下一个观察是:假设你有一个大小为2k+1的数组,在这种情况下,假设你在数组的两边各放一个1。然后:
重要的一点是,产生的位模式是1和0的交替序列。例如:
这很重要的原因是:假设数组中有n个元素,k是2k+1≤n的最大可能值。如果将1放在位置2k+1,则数组左侧到该位置的部分将以交替的1和0平铺,它将一个1s的批放入数组中。在
不明显的是,把1位放在那里,对于5万以内的所有数字,似乎会产生一个最佳的解决方案!我已经编写了一个Python脚本来检查这一点(使用一个类似于@justhalf的递归关系),它似乎工作得很好。这个事实如此有用的原因是计算这个指数非常容易。特别是,如果2k+1≤n,则2k≤n-1,因此k≤lg(n-1)。选择值⌊lg(n-1)⌋作为k的选择,然后通过计算2k+1来计算位索引。这个k值可以在O(logn)时间内计算,求幂也可以在O(logn)时间内完成,因此总运行时间为Θ(logn)。在
唯一的问题是我还没有正式证明这是有效的。我只知道,对于我们尝试的前50000个值来说,这是正确的。:-)
希望这有帮助!在
我会附上我所有的。和你的一样,唉,时间基本上是
O(n**3)
。但至少它避免了递归(等等),所以当你接近一百万时不会爆炸;-)注意,这返回找到的最佳向量,而不是计数;例如所以它也显示了选择1位的顺序。获取计数的最简单方法是将结果传递给
^{pr2}$max()
。在或者将函数更改为返回
maxsofar
,而不是best
。在如果你想计算一百万的数字,你需要的是完全不同的东西。你甚至负担不起二次方时间(更不用说这种方法的立方时间了)。不太可能从更华丽的数据结构中得到如此巨大的改进,我希望它需要对问题的数学有更深入的了解。在
相关问题 更多 >
编程相关推荐