根据某些约束来计算组合总数的算法

发布于 2025-02-10 05:45:07 字数 396 浏览 0 评论 0原文

我有一些应该组合的字母。 该字母应在相应的地方合并,并选择省略一些字母。 例如,

对于A,我有A1,A2,A3。

对于B,我有B1,B2。

对于C,我有C1,C2,C3,C4。

对于D,我有D1,D2。

组合的一个例子是A1,B2,C1,D2。另一个可能的组合是_,b2,c1,d2(省略字母A)。

没有任何约束,总组合将为(3+1)(2+1)(4+1)(2+1)= 180组合。

但是,我想根据一些约束来计算总组合。 例如,基于[A1不能与B2一起出现]的约束,并且[A2不能与C4一起出现]总组合小于180。

我知道这可以通过包容性排斥原则来完成,但是这是非常困难的为了编程包含,排除计算。还有其他算法,而不是包容性排斥原则和蛮力吗?

非常感谢!!

I have some set of letters that should be combined.
The letter should be combined in corresponding places with a choice of omitting some letter.
For example,

For A, I have A1, A2, A3.

For B, I have B1, B2.

For C, I have C1, C2, C3, C4.

For D, I have D1, D2.

One example of the combination is A1,B2,C1,D2. Another possible combination is _,B2,C1,D2 (omitting letter A).

Without any constraints, the total combinations would be (3+1)(2+1)(4+1)(2+1) = 180 combinations.

However, I would like to count the total combinations based on some constraints.
For example, on the constraint that [A1 cannot occur together with B2] and [A2 cannot occur together with C4] the total combination would be less than 180.

I know this could be done with inclusion-exclusion principle, but it is quite difficult to program the inclusion, exclusion calculation. Is there any other algorithms rather than the inclusion-exclusion principle and brute force?

Thank you very much!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人间☆小暴躁 2025-02-17 05:45:07

我相信您高估了编码包容性排斥的努力。

class LetterRule:
    def __init__ (self, letter, positions):
        self.letter = letter
        if isinstance(positions, list):
            self.positions = positions
        else:
            self.positions = [positions]

def count_matching_combinations (letter_allowed):
    answer = 1
    for allowed in letter_allowed.values():
        answer *= len(allowed)
    return answer

def matching_rule_allowed (letter_allowed, rule):
    # Make a copy
    letter_allowed = letter_allowed.copy()
    for letter_rule in rule:
        allowed = letter_allowed[letter_rule.letter]
        allowed = [x for x in allowed if x in letter_rule.positions]
        if 0 == len(allowed):
            return None
        letter_allowed[letter_rule.letter] = allowed
    return letter_allowed

# This is the inclusion-exclusion logic.
def matching_combination_counts (letter_allowed, rules, i=None, sign=1):
    if i is None:
        yield(count_matching_combinations(letter_allowed))
        for i in range(len(rules)):
            yield from matching_combination_counts(
                letter_allowed, rules, i, -1)

    else:
        letter_allowed = matching_rule_allowed(letter_allowed, rules[i])
        if letter_allowed is not None:
            yield sign * count_matching_combinations(letter_allowed)
            for j in range(i+1, len(rules)):
                yield from matching_combination_counts(
                    letter_allowed, rules, j, sign * -1)

def count_combinations (letter_allowed, rules=None):
    if rules is None:
        rules = []
    return sum(matching_combination_counts(letter_allowed, rules))


letter_allowed = {
    'A': [0, 1, 2, 3],
    'B': [0, 1, 2],
    'C': [0, 1, 2, 3, 4],
    'D': [0, 1, 2],
}
rules = [
    [LetterRule('A', 1), LetterRule('B', 2)],
    [LetterRule('A', 2), LetterRule('C', 4)],
]
print(count_combinations(letter_allowed, rules))

I believe that you are overestimating the effort of coding inclusion-exclusion.

class LetterRule:
    def __init__ (self, letter, positions):
        self.letter = letter
        if isinstance(positions, list):
            self.positions = positions
        else:
            self.positions = [positions]

def count_matching_combinations (letter_allowed):
    answer = 1
    for allowed in letter_allowed.values():
        answer *= len(allowed)
    return answer

def matching_rule_allowed (letter_allowed, rule):
    # Make a copy
    letter_allowed = letter_allowed.copy()
    for letter_rule in rule:
        allowed = letter_allowed[letter_rule.letter]
        allowed = [x for x in allowed if x in letter_rule.positions]
        if 0 == len(allowed):
            return None
        letter_allowed[letter_rule.letter] = allowed
    return letter_allowed

# This is the inclusion-exclusion logic.
def matching_combination_counts (letter_allowed, rules, i=None, sign=1):
    if i is None:
        yield(count_matching_combinations(letter_allowed))
        for i in range(len(rules)):
            yield from matching_combination_counts(
                letter_allowed, rules, i, -1)

    else:
        letter_allowed = matching_rule_allowed(letter_allowed, rules[i])
        if letter_allowed is not None:
            yield sign * count_matching_combinations(letter_allowed)
            for j in range(i+1, len(rules)):
                yield from matching_combination_counts(
                    letter_allowed, rules, j, sign * -1)

def count_combinations (letter_allowed, rules=None):
    if rules is None:
        rules = []
    return sum(matching_combination_counts(letter_allowed, rules))


letter_allowed = {
    'A': [0, 1, 2, 3],
    'B': [0, 1, 2],
    'C': [0, 1, 2, 3, 4],
    'D': [0, 1, 2],
}
rules = [
    [LetterRule('A', 1), LetterRule('B', 2)],
    [LetterRule('A', 2), LetterRule('C', 4)],
]
print(count_combinations(letter_allowed, rules))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文