C#:没有重复的骰子排列

时间:2012-07-07 07:18:00

标签: c# math permutation combinatorics

如何更改下面的C#代码以列出所有可能的排列而不重复?例如:2个骰子卷的结果将产生1,1,2,因此不应出现2,1,1。

以下是我的代码:

string[] Permutate(int input)
{
        string[] dice;
        int numberOfDice = input;
        const int diceFace = 6;
        dice = new string[(int)Math.Pow(diceFace, numberOfDice)];
        int indexNumber = (int)Math.Pow(diceFace, numberOfDice);
        int range = (int)Math.Pow(diceFace, numberOfDice) / 6;

        int diceNumber = 1;
        int counter = 0;

        for (int i = 1; i <= indexNumber; i++)
        {
            if (range != 0)
            {
                dice[i - 1] += diceNumber + " ";
                counter++;
                if (counter == range)
                {
                    counter = 0;
                    diceNumber++;
                }
                if (i == indexNumber)
                {
                    range /= 6;
                    i = 0;
                }
                if (diceNumber == 7)
                {
                    diceNumber = 1;
                }
            }
            Thread.Sleep(1);
        }
        return dice;
    }

5 个答案:

答案 0 :(得分:5)

我能想到的最简单的方式:

List<string> dices = new List<string>();
for (int i = 1; i <= 6; i++)
{
    for (int j = i; j <= 6; j++)
    {
        for (int k = j; k <= 6; k++)
        {
            dices.Add(string.Format("{0} {1} {2}", i, j, k));
        }
    }
}

答案 1 :(得分:1)

我编写了一个类来处理使用二项式系数的常用函数,这是您的问题所处的问题类型。它执行以下任务:

  1. 以任意N选择K到文件的格式输出所有K索引。 K索引可以用更具描述性的字符串或字母代替。这种方法使解决这类问题变得非常简单。

  2. 将K索引转换为已排序二项系数表中条目的正确索引。这种技术比依赖迭代的旧发布技术快得多。它通过使用Pascal三角形中固有的数学属性来实现。我的论文谈到了这一点。我相信我是第一个发现和发布这种技术的人,但我可能错了。

  3. 将已排序的二项系数表中的索引转换为相应的K索引。

  4. 使用Mark Dominus方法计算二项式系数,这样就不太可能溢出并使用更大的数字。

  5. 该类是用.NET C#编写的,它提供了一种通过使用通用列表来管理与问题相关的对象(如果有)的方法。此类的构造函数采用名为InitTable的bool值,当为true时,将创建一个通用列表来保存要管理的对象。如果此值为false,则不会创建表。不需要创建表来执行上述4种方法。提供访问者方法来访问该表。

  6. 有一个关联的测试类,它显示了如何使用该类及其方法。它已经过2个案例的广泛测试,并且没有已知的错误。

  7. 要阅读此课程并下载代码,请参阅Tablizing The Binomial Coeffieicent

答案 2 :(得分:0)

我也很擅长数学,这可能有用也可能没有用......

<强> Program.cs的

namespace Permutation
{
    using System;
    using System.Collections.Generic;

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Generating list.");

            var dice = new List<ThreeDice>();

            for (int x = 1; x <= 6; x++)
            {
                for (int y = 1; y <= 6; y++)
                {
                    for (int z = 1; z <= 6; z++)
                    {
                        var die = new ThreeDice(x, y, z);

                        if (dice.Contains(die))
                        {
                            Console.WriteLine(die + " already exists.");
                        }
                        else
                        {
                            dice.Add(die);
                        }
                    }
                }
            }

            Console.WriteLine(dice.Count + " permutations generated.");

            foreach (var die in dice)
            {
                Console.WriteLine(die);
            }

            Console.ReadKey();
        }
    }
}

ThreeDice.cs

namespace Permutation
{
    using System;
    using System.Collections.Generic;

    public class ThreeDice : IEquatable<ThreeDice>
    {
        public ThreeDice(int dice1, int dice2, int dice3)
        {
            this.Dice = new int[3];
            this.Dice[0] = dice1;
            this.Dice[1] = dice2;
            this.Dice[2] = dice3;
        }

        public int[] Dice { get; private set; }

        // IEquatable implements this method. List.Contains() will use this method to see if there's a match.
        public bool Equals(ThreeDice other)
        {
            // Get the current dice values into a list.
            var currentDice = new List<int>(this.Dice);

            // Check to see if the same values exist by removing them one by one.
            foreach (int die in other.Dice)
            {
                currentDice.Remove(die);
            }

            // If the list is empty, we have a match.
            return currentDice.Count == 0;
        }

        public override string ToString()
        {
            return "<" + this.Dice[0] + "," + this.Dice[1] + "," + this.Dice[2] + ">";
        }
    }
}
祝你好运。

答案 3 :(得分:0)

问题的重要部分是你需要不同的集合(无论顺序如何)。因此,例如,[1,2,1]的骰子卷等于[1,1,2]的骰子卷。

我确信有很多方法可以让这只猫变老,但首先想到的是创建一个EqualityComparer,它会以你想要的方式比较骰子列表,然后使用LINQ和Distinct()方法。

以下是EqualityComparer,其中2 List<int>表示如果元素全部相等(无论顺序如何),它们是相等的:

    private class ListComparer : EqualityComparer<List<int>>
    {
        public override bool Equals(List<int> x, List<int> y)
        {
            if (x.Count != y.Count)
                return false;
            x.Sort();
            y.Sort();
            for (int i = 0; i < x.Count; i++)
            {
                if (x[i] != y[i])
                    return false;
            }
            return true;
        }
        public override int GetHashCode(List<int> list)
        {
            int hc = 0;
            foreach (var i in list)
                hc ^= i;
            return hc;
        }
    }

这是使用它的代码。我正在使用LINQ来构建所有组合的列表......你也可以使用嵌套的for循环执行此操作,但出于某种原因我更喜欢这样:

    public static void Main()
    {
        var values = new[] { 1,2,3,4,5,6 };
        var allCombos = from x in values
                        from y in values
                        from z in values
                        select new List<int>{ x, y, z };
        var distinctCombos = allCombos.Distinct(new ListComparer());

        Console.WriteLine("#All combos: {0}", allCombos.Count());
        Console.WriteLine("#Distinct combos: {0}", distinctCombos.Count());
        foreach (var combo in distinctCombos)
            Console.WriteLine("{0},{1},{2}", combo[0], combo[1], combo[2]);
    }

希望有所帮助!

答案 4 :(得分:0)

这是使用递归的通用c#版本(基本上递归方法需要骰子的数量或掷骰子的次数)并返回所有组合字符串(例如,根据问题为'3' - 将会是56这样的组合)。

public string[] GetDiceCombinations(int noOfDicesOrnoOfTossesOfDice)
        {
            noOfDicesOrnoOfTossesOfDice.Throw("noOfDicesOrnoOfTossesOfDice",
                n => n <= 0);
            List<string> values = new List<string>();
            this.GetDiceCombinations_Recursive(noOfDicesOrnoOfTossesOfDice, 1, "",
                values);
            return values.ToArray();
        }
        private void GetDiceCombinations_Recursive(int size, int index, string currentValue,
            List<string> values)
        {
            if (currentValue.Length == size)
            {
                values.Add(currentValue);
                return;
            }
            for (int i = index; i <= 6; i++)
            {
                this.GetDiceCombinations_Recursive(size, i, currentValue + i, values);
            }
        }

以下是相应的测试......

[TestMethod]
        public void Dice_Tests()
        {
            int[] cOut = new int[] { 6, 21, 56, 126 };
            for(int i = 1; i<=4; i++)
            {
                var c = this.GetDiceCombinations(i);
                Assert.AreEqual(cOut[i - 1], c.Length);
            }
        }