按标准递归分配集合

时间:2017-05-02 00:18:17

标签: python recursion

所以我试图解决递归分配问题。
本质上,对于集合A中的每个元素,我试图从集合B中分配一个元素,其中| A | < = | B |。 来自B的元素只能分配给A中的一个元素,并且只有在满足“安全”标准时才能分配。
在python中编写这个问题的较小版本(使用更简单的安全检查)会得到以下结果,其中f(A,B)返回配对分配集,假设你有一组B要分配设置A

A = ["A0","A1","A2"]
B = ["B0","B1","B2","B3"]

def issafe(a,b):
    return int(a[1]) <= int(b[1])

def f(A,B):
    if A == []:
        return []
    else:
        for i in range(len(B)):
            if issafe(A[0],B[i]):
                 return [(A[0],B[i])] + f(A[1:],B[0:i]+B[i+1:])

所以使用初始集运行函数

f(A,B)
=> [('A0', 'B0'), ('A1', 'B1'), ('A2', 'B2')]

这是从b到a的安全分配。然而,只有一种可能的安全分配。 我希望有人可以给我一些关于如何扩展这个解决方案的指导,以便它提供所有安全的分配。

所以类似

f(A,B)
=> [[('A0', 'B0'), ('A1', 'B1'), ('A2', 'B2')],
    [('A0', 'B1'), ('A1', 'B2'), ('A2', 'B3')],
    [                  ...                   ]]


<小时/>
根据Prune的评论进行更改:

def f(A,B):
    C = []
    if A == []:
        return []
    else:
        for i in range(len(B)):
            if issafe(A[0],B[i]):
                C.append([(A[0],B[i])] + f(A[1:],B[0:i]+B[i+1:]))
    return C

这给出了树结构的输出:

[
[('A0', 'B0'),[('A1', 'B1'), [('A2', 'B2')], [('A2', 'B3')]], [('A1', 'B2'), [('A2', 'B3')]], [('A1', 'B3'), [('A2', 'B2')]]], 
[('A0', 'B1'), [('A1', 'B2'), [('A2', 'B3')]], [('A1', 'B3'), [('A2', 'B2')]]], 
[('A0', 'B2'), [('A1', 'B1'), [('A2', 'B3')]], [('A1', 'B3')]], 
[('A0', 'B3'), [('A1', 'B1'), [('A2', 'B2')]], [('A1', 'B2')]]
]

我认为这是正确的,但我仍然不确定是否有一种方法可以将自己的安全分配集合作为一个树来实现。

3 个答案:

答案 0 :(得分:0)

典型的方法是递归的。在给定的电话上:

  • 基本情况: 如果A或B都是空的,那么你就完成了;返回。

  • 递归案例:

    • 对于A的第一个元素,依次尝试B的每个元素(即用于循环)。如果该配对合法,则重复使用剩余列表。
    • 连接/追加所有成功的分配并将其返回到下一级别。

这会让你走向解决方案吗?

答案 1 :(得分:0)

值得注意的是,这将主要由列表创建和连接主导。迭代器是解决这个问题的好方法,例如:

def allsafe(x, y):
      if not x:
          yield ()
      else:
          v_x = x[0]
          remaining = x[1:]
          for i, v_y in enumerate(y):
              if not issafe(v_x, v_y):
                  continue
              point = (v_y, )
              if remaining:
                  for solution in allsafe(remaining, y[:i]):
                      yield point + solution
                  for solution in allsafe(remaining, y[i+1:]):
                      yield point + solution
              else:
                  yield point

def test():
    a = ["A%d" % i for i in xrange(6)]
    b = ["B%d" % i for i in xrange(30)]
    for b_solution in allsafe(a, b):
        # Don't print with large a/b sizes if you value your terminal history
        print 'solution: %s' % zip(a, list(b_solution))

请注意,我使用了元组和拉链,但它们并不重要。对于给定的大小(|A|=6|B|=30),运行速度提高约15倍,6,32的速度提高约20倍,6,35等的速度提高约25倍

答案 2 :(得分:0)

所以我最终做的是在函数中添加一个输入来存储到目前为止已分配的内容和一个用于存储已保存的solns的输入。然后,当我达到结束条件时,我将分配的对存储到soln中,换句话说

def f(A,B,Assigned = [],Soln = []):
C = []
#If we've assigned all A's
if A == []:
  #Add this assignment list to soln list
  Soln.append(Assigned)
  #Return blank to stop recursion
  return ([],Soln)
else:
    for i in range(len(B)):
      #For unassigned safe B's
        if issafe(A[0],B[i]):
            C.append(   [(A[0],B[i])]               #Newly assigned pair
                      + [f(A[1:], B[0:i] + B[i+1:], #Remainder to be assigned
                         Assigned + [(A[0],B[i])],  #Update assigned list
                         Soln)[0]])                 #'Transfer' soln to next itteration 
return (C,Soln)

Ans = f(AInit,BInit)[1]

for a in Ans:
  print (a)

这产生了我所追求的解决方案,据我所知,它可以用于任何一组A和B以及各种安全配置

[('A0', 'B0'), ('A1', 'B1'), ('A2', 'B2')]
[('A0', 'B0'), ('A1', 'B1'), ('A2', 'B3')]
[('A0', 'B0'), ('A1', 'B2'), ('A2', 'B3')]
[('A0', 'B0'), ('A1', 'B3'), ('A2', 'B2')]
[('A0', 'B1'), ('A1', 'B2'), ('A2', 'B3')]
[('A0', 'B1'), ('A1', 'B3'), ('A2', 'B2')]
[('A0', 'B2'), ('A1', 'B1'), ('A2', 'B3')]
[('A0', 'B3'), ('A1', 'B1'), ('A2', 'B2')]

感谢Prune的帮助和建议