首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我怎么知道谁能在圣诞节送礼物给谁?

我怎么知道谁能在圣诞节送礼物给谁?
EN

Stack Overflow用户
提问于 2012-10-26 14:57:04
回答 2查看 1.3K关注 0票数 8

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

代码语言:javascript
复制
["John", "James", "Jenna", "Joseph", "Jane", "Jacob", "Joanne"]

他们都在为圣诞礼物赠送季节做准备。他们已经商定了一些规则,以确保一切顺利进行:

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

由于规则如此复杂,他们很难弄清楚谁能在遵守这些规则的同时给予谁。因此,他们雇佣我来编写一个程序,展示人们可以相互给予的所有可能的合法方式。

我能用什么算法巧妙地解决这个问题呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-10-30 10:52:31

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

代码语言:javascript
复制
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

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

代码语言:javascript
复制
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是送礼者和-receivers的dict,例如{'joanne': 'joseph', 'james': 'john', 'jane': 'joanne', 'joseph': 'jacob', 'jacob': 'jane', 'john': 'jenna', 'jenna': 'james'}

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

票数 4
EN

Stack Overflow用户

发布于 2012-10-26 16:43:33

如果您从一个7x7网格开始,每个人都有一行和一列,表示是否允许行中提到的人给列中提到的人送礼物。

首先,将每个组合标记为允许的,然后开始删除那些被约束条件3、4和5明显不允许的组合。每个有效的礼物组合都必须是您在此时留下的组合的子集。这将是你的起始位置。

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

如果你以结构化的方式尝试所有的可能性,你一定会找到所有的解决方案,如果它们存在的话。

现在,让他们的钱值:)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13089352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档