从已保存的状态

时间:2016-07-16 19:52:35

标签: algorithm recursion vbscript

我有一个递归函数,它从一组n中产生长度为k的所有组合。通常称为“nCk”(“n选择k”)。我希望用相当大的值(56C22)来放松它,这将产生2,142,582,442,263,900个结果。由于实施限制(我必须使用VBScript,并且不能保持登录计算机的时间比我工作的时间长),我将无法让它一次性完成运行。因此,我想定期保存函数的当前状态并在以后恢复...但我似乎无法弄清楚如何这样做。递归正在弄乱我通过逻辑思考这个问题的能力。

我已经在SO上仔细阅读了建议的解决方案,否则搜索“恢复递归函数”等等,但无济于事。我会很感激一些指针(不是编程语言双关语)让我走上正轨。

实际算法(伪代码很好)优于不包含实际代码的冗长解释。如果你想实际编写代码,我最熟悉的是C,C ++,Pascal,VB,JavaScript和VBScript(如上所述,目前正在使用VBScript)。

这是我的递归函数:

function nCk(aSet, iSetIndex, aSubset, iSubsetIndex)
    'Found result
    if (iSubsetIndex > ubound(aSubset)) then
        log "output.txt", join(aSubset), 1, false

        exit function
    end if

    'No more characters available
    if (iSetIndex >= ubound(aSet) + 1) then
        exit function
    end if

    'With aSet[iSetIndex]
    aSubset(iSubsetIndex) = aSet(iSetIndex)
    nCk aSet, iSetIndex + 1, aSubset, iSubsetIndex + 1

    'Without
    nCk aSet, iSetIndex + 1, aSubset, iSubsetIndex
end function  'nCk

仅供参考:我今年50岁;这不是作业。

2 个答案:

答案 0 :(得分:0)

我不确定您的特定语言实现,但我相信在某些情况下将递归转换为迭代是有用的。当你有一个明确的堆栈时,将它写入光盘并从你离开的地方拿起来应该不会太复杂。

一般例子:

stack = [[argument1,argument2,argument3,...etc.]]

while stack is not empty
  current_parameters = stack.pop

  aSet      = current_parameters[0]
  iSetIndex = current_parameters[1]
  ...etc.

  if ...

else ...
    // push to stack instead of calling nCk
    stack.push([aSet, iSetIndex + 1, aSubset, iSubsetIndex + 1])

if it's time to go home
    write stack to disc
    break

答案 1 :(得分:0)

存储递归并不容易,因为要恢复操作,您需要恢复堆栈,这不是一项简单的任务。我会使用迭代算法,这不像递归那样优雅。但如果需要中断/恢复计算,它会得到回报。

一个想法可能是:

  1. 子集表示为0和1的向量。 0表示不取元素,1 - 取元素,因此集合{1,2,3}的[1,0,1]表示子集{1,3}。显然,只有长度为N的矢量才是真实的子集。
  2. 将此向量视为一种堆栈,它表示“递归”的状态
  3. 此向量中的值-1用于在迭代中触发正确的行为 - >类似于从递归返回/回溯。
  4. 作为算法(首先,迭代所有子集):

    def calc_subsets(state, N):#N - number of elements in the original set
         while True: #just iterate
            if storeFlag:#you need to set this flag to store and interrupt
                store(state)
                return
            if len(state)==N and state[-1]!=-1: #a full subset is reached
                evaluate(state)
                state.append(-1)#mark for unwind
    
            if state[-1]==-1:#means unwind state
                state.pop()
                if not state: #state is empty
                    return #unwinded last element, we are done
                if state[-1]==1:#there is noting more to be explored
                   state[-1]=-1#mark for unwind in the next iteration
                else:# = 0 is explored, so 1 is the next to explore
                   state[-1]=1
            else: #means explore
                state.append(0) # 0 is the first to explore
    

    evaluate取决于你,我只打印出矢量:

    def evaluate(state):
        print state
    

    要打印3个元素的所有子集,应该调用:

    calc_subsets([0], 3)
    >>>
    [0, 0, 0]
    [0, 0, 1]
    [0, 1, 0]
    [0, 1, 1]
    [1, 0, 0]
    [1, 0, 1]
    [1, 1, 0]
    [1, 1, 1]
    

    并仅打印第二部分:

    calc_subsets([0,1,1,-1], 3) 
    >>>
    [1, 0, 0]
    [1, 0, 1]
    [1, 1, 0]
    [1, 1, 1]
    

    现在,该算法可以适用于仅通过给定基数的所有子集进行迭代。为此,必须跟踪当前子集中的元素数量并触发展开(通过将-1推入状态向量),如果实现了所请求的子集大小。