【问题标题】:Dice combinations to a total骰子组合总数
【发布时间】:2021-10-04 08:23:40
【问题描述】:

试图找到一个很好的算法来计算 d4 骰子组合的总数。例如 3 个有四个面的骰子,所有组成 4 的组合将给出:004 013 112 022

我将使用 c#,但 python 或 pseudo 会很棒。只是需要一些算法的帮助。将始终是一个四面骰子,但骰子的总数和数量将是参数。

任何想法都会很棒。谢谢。

【问题讨论】:

  • 所以 004 意味着你实际上只掷三个骰子之一?
  • 是的。所以这是骰子的最大数量。我认为使用 for 循环的大多数方式。每个骰子一个,但这是一个变量。

标签: algorithm dice die


【解决方案1】:

你可以使用递归。

例如,在 Python 中它看起来像这样:

def combis(num_dice, target, minval=1):
    if target == 0:
        return [""]  # solution
    if num_dice < 1 or target < 0:
        return [] # no solution

    res = []
    for side in range(minval, min(5, target + 1)):
        for combi in combis(num_dice - 1, target - side, side):
            res.append(str(side) + combi)
    return res
    
print(combis(3, 4))

如果这真的必须在 Python 中完成,那么可以使用像 itertools 这样的库。

输出是一个字符串列表,其中字符串中的每个字符都是代表骰子侧面的数字。字符串永远不会比第一个参数 (num_dice) 长,但它们可以更短,这意味着涉及的骰子更少。如果需要,您可以用“0”填充它们。

C#实现

using System;
using System.Collections;

class MainClass {
    public static ArrayList combis(int numDice, int target, int minval=1) {
        var res = new ArrayList();
        if (target == 0) {
            res.Add(""); // solution
        } else if (numDice > 0 && target > 0) {
            for (int side = minval; side < 5 && side <= target; side++) {
                foreach (var combi in combis(numDice - 1, target - side, side)) {
                    res.Add(side.ToString() + combi);
                }
            }
        }
        return res;
    }

    public static void Main (string[] args) {
        // Example run
        foreach (var combi in combis(3, 4)) {
            Console.WriteLine (combi);
        }
    }
}

【讨论】:

  • 太好了,谢谢,我在想我可能不得不走递归路线。
  • 嵌入 for 循环的 C# 有问题....
  • 我在答案中添加了一个 C# 实现。我的 C# 不是很流利,所以它可能会有所改进。
【解决方案2】:

这是对 trincot 的 answer 的一个调整,它不需要创建中间列表,它会计算当前骰子的最小值,从而减少浪费的调用 (.Net Fiddle)。

public static ArrayList combos(int nDice, int tot, int max)
{
    var res = new ArrayList();
    combos(res, "", nDice, tot, max);
    return res;
}

private static void combos(ArrayList res, String sol, int nDice, int tot, int max)
{
    if(tot == 0)
    {
        res.Add(sol);
        return;
    }
    
    for(int side = 1+(tot-1)/nDice; side <= Math.Min(tot, max); side++)
        combos(res, sol+side, nDice-1, tot-side, side);
}

测试:

public static void Main (string[] args) {
    int nDice = 3;
    int nFaces = 4;
    for(int tot=1; tot<=nDice*nFaces+1; tot++)
    {
        Console.WriteLine ("\nTot: " + tot);
        foreach (var combo in combos(nDice, tot, nFaces)) {
            Console.WriteLine (combo);
        }
    }
}

输出:

tot: 1
1

tot: 2
11
2

tot: 3
111
21
3

tot: 4
211
22
31
4

tot: 5
221
311
32
41

tot: 6
222
321
33
411
42

tot: 7
322
331
421
43

tot: 8
332
422
431
44

tot: 9
333
432
441

tot: 10
433
442

tot: 11
443

tot: 12
444

tot: 13

【讨论】:

    猜你喜欢
    • 2019-11-06
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 1970-01-01
    • 2020-10-25
    • 2015-07-03
    • 2012-11-09
    • 1970-01-01
    相关资源
    最近更新 更多