【发布时间】:2016-01-11 03:54:06
【问题描述】:
这是我从昨晚开始想到的一个谜题。我想出了一个解决方案,但效率不高,所以我想看看是否有更好的主意。
谜题是这样的:
给定正整数 N 和 T,您需要:
for i in [1, T], A[i] from { -1, 0, 1 }, such that SUM(A) == N
additionally, the prefix sum of A shall be [0, N], while when the prefix sum PSUM[A, t] == N, it's necessary to have for i in [t + 1, T], A[i] == 0
here prefix sum PSUM is defined to be: PSUM[A, t] = SUM(A[i] for i in [1, t])
the puzzle asks how many such A's exist given fixed N and T
例如,当N = 2,T = 4,跟随As工作时:
1 1 0 0
1 -1 1 1
0 1 1 0
但以下不要:
-1 1 1 1 # prefix sum -1
1 1 -1 1 # non-0 following a prefix sum == N
1 1 1 -1 # prefix sum > N
以下python代码可以验证这样的规则,当给定N为expect和一个A的实例为seq时(有些人可能觉得阅读代码比阅读文字描述更容易):
def verify(expect, seq):
s = 0
for j, i in enumerate(seq):
s += i
if s < 0:
return False
if s == expect:
break
else:
return s == expect
for k in range(j + 1, len(seq)):
if seq[k] != 0:
return False
return True
我已经编写了我的解决方案,但它太慢了。以下是我的:
我将问题分解为两部分,其中没有-1 的部分(只有{0, 1} 和-1 的部分。
所以如果SOLVE(N, T) 是正确答案,我定义了一个函数SOLVE'(N, T, B),其中正数B 允许我将前缀总和扩展到[-B, N] 的区间内,而不是[0, N]
事实上SOLVE(N, T) == SOLVE'(N, T, 0)。
所以我很快意识到解决方案实际上是:
- A 的前缀是一些有效的
{0, 1}组合与正长度l,并在其中包含o1s - 在
l + 1的位置,我开始添加1个或多个-1s并使用B来跟踪数字。最大值为B + o或取决于A中剩余的插槽数,以较小者为准。 - 递归调用
SOLVE'(N, T, B)
在前面的N = 2, T = 4 示例中,在其中一个搜索案例中,我会这样做:
- 设A的前缀为[1],则有
A = [1, -, -, -]。 - 开始添加
-1。这里我只添加一个:A = [1, -1, -, -]。 - 递归调用
SOLVE',这里我会调用SOLVE'(2, 2, 0)来解决最后两个点。在这里它只会返回[1, 1]。然后其中一种组合产生[1, -1, 1, 1]。
但是这个算法太慢了。
我想知道如何优化它或以任何不同的方式来看待这个可以提高性能的问题?(我只需要这个想法,而不是实现)
编辑:
一些样本将是:
T N RESOLVE(N, T)
3 2 3
4 2 7
5 2 15
6 2 31
7 2 63
8 2 127
9 2 255
10 2 511
11 2 1023
12 2 2047
13 2 4095
3 3 1
4 3 4
5 3 12
6 3 32
7 3 81
8 3 200
9 3 488
10 3 1184
11 3 2865
12 3 6924
13 3 16724
4 4 1
5 4 5
6 4 18
指数时间解决方案通常如下(在 python 中):
import itertools
choices = [-1, 0, 1]
print len([l for l in itertools.product(*([choices] * t)) if verify(n, l)])
【问题讨论】:
-
您能否提供一些测试输入和输出,并说明您当前的算法在这些方面需要多长时间?
-
@MarkDickinson 更新了一些示例输出。我当前的 impl 需要几秒钟才能解决
SOLVE(10, 100). -
谢谢!不过,我不确定我是否相信这些输入和输出。对于第一个(T = N = 3),不是 [1, 1, 1] 唯一的解决方案吗?我错过了哪两个解决方案?
-
@MarkDickinson 我将 N 加了一个。现在它已经修复了。
-
好的,他们同意我的解决方案(我为
solve(10, 100)花费了大约 1 毫秒,结果为250639233987229485923025924628548154758061157)。我会发布我的解决方案。
标签: algorithm