我如何知道谁可以在圣诞节给谁送礼物?

时间:2012-10-26 14:57:05

标签: algorithm language-agnostic

我们假设有一个七口之家,比如说,

["John", "James", "Jenna", "Joseph", "Jane", "Jacob", "Joanne"]
他们都准备好迎接圣诞节送礼季节。他们已就一些规则达成一致,以确保一切顺利进行:

  • 每个人都必须赠送一份礼物。
  • 每个人都必须收到一份礼物。
  • 没有人可以给自己送礼物。
  • 没有人可以给他的配偶送礼物。 (简和约翰是配偶)
  • 没有人可以给去年给他的同一个人。 (去年,约翰送给詹姆斯,詹姆斯送给珍娜,珍娜送给约瑟,约瑟送给简,简给雅各布,雅各送给乔安妮,乔安妮送给约翰)
  • 最后,没有两个人可以互赠礼物。例如,如果John给Jenna,Jenna可能不会回馈John。

由于规则虽然复杂,但他们很难弄清谁在遵守这些规则的同时可以给谁。因此,他们聘请我编写一个程序,显示人们可以互相给予的所有合法方式。

我可以使用哪些算法来优雅地解决这个问题?

2 个答案:

答案 0 :(得分:4)

我会使用简单的回溯算法。使用Python生成器函数:

def calc_gifts(names, blacklist, gifts={}):
    if len(names) > 0:
        name, rest = names[0], names[1:]
        for other in names + list(gifts):
            if (other != name and 
                    other not in blacklist[name] and
                    (other not in gifts or gifts[other] != name) and
                    other not in gifts.values()):

                gifts_new = dict(gifts.items() + [(name, other)])
                for solution in calc_gifts(rest, blacklist, gifts_new):
                    yield solution
    else:
        yield gifts

现在,我们设置名称和黑名单,让生成器生成解决方案:

all_names = ["john", "james", "jenna", "joseph", "jane", "jacob", "joanne"]
blacklist = {"john":   ["james", "jane"],
             "james":  ["jenna"],
             "jenna":  ["joseph"],
             "joseph": ["jane"],
             "jane":   ["jacob", "john"],
             "jacob":  ["joanne"],
             "joanne": ["john"]}
generator = calc_gifts(all_names, blacklist)
solution = next(generator)

solution然后是dict赠送者和接收者,例如{'joanne': 'joseph', 'james': 'john', 'jane': 'joanne', 'joseph': 'jacob', 'jacob': 'jane', 'john': 'jenna', 'jenna': 'james'}

对于第一个解决方案,即使用next(generator)calc_gifts仅被调用10次;对所有224个解决方案,例如使用list(generator)它被调用约。 1000次。

答案 1 :(得分:1)

如果您从7x7网格开始,每个人都有一行和一列,表明该行中提到的人是否可以向该列中提到的人赠送礼物,该怎么办?

最初,将每个组合标记为允许,然后开始删除约束3,4和5明确禁止的组合。每个有效的礼物组合必须是您的组合的一部分已经离开了这一点。这将是你的起始位置。

现在你必须开始做出决定,每一个决定都会影响你留下的可能性。有些决定可能会成错,导致不是每个人最终都会得到礼物。在这种情况下,您应该收回该决定并尝试另一个(提示:使用递归)。

如果您以结构化的方式尝试所有可能性,那么您必定会找到所有解决方案。

现在,赚钱是值得的:)。