将元素排列在任何大小的矩阵中

时间:2016-07-20 12:31:13

标签: c# matrix random distribution

这是一个讨论而不是问题,因为我可以用代码来解决这个问题,但我认为应该有更好的方法来做到这一点。

我需要在矩阵中分配元素,以便矩阵的每个象限(其尺寸不能被4整除)包含相等(或尽可能接近相等)的所述元素数量但位于在该象限内随机出现。 矩阵的其余部分需要包含不同类型的随机元素。

例如,在9x6矩阵中分配10个元素(A)可能如下所示:

enter image description here

这揭示了当维度为奇数时如何处理中间线的问题。它可以随机包含在一个象限或另一个象限中(事实上3个中间列中没有As只是偶然)

我首先考虑使用递归函数来处理这个问题,该函数分为象限并随机放置每个元素。

我在C#编写这个代码的过程中,这个想法是这样的(它现在还不起作用,而且有些事情试图使代码更具可读性是无效的):

private void PopulateQuadrants(ref Test5Target[,] matrix,
        int xBeginQuadrant, int xEndQuadrant, int yBeginQuadrant, int yEndQuadrant, int targets)
    {
        if (targets == 0)
        {
            return;
        }
        else if (targets == 1)
        {
            Random rand = new Random();
            matrix[rand.Next(xBeginQuadrant, xEndQuadrant), rand.Next(yBeginQuadrant, yEndQuadrant)]
                = new Test5Target(ChosenTarget, UseAdvancedTargets);
            for (int x = xBeginQuadrant; x < xEndQuadrant; x++)
            {
                for (int y = xBeginQuadrant; y < xEndQuadrant; y++)
                {
                    if (matrix[x, y] == null)
                    {
                        int type = rand.Next(TargetCount);
                        while(type == ChosenTarget){
                            type = rand.Next(TargetCount);
                        }

                        matrix[x, y] = new Test5Target(rand.Next(TargetCount), UseAdvancedTargets);
                    }
                }
            }

            return;
        }
        else
        {
            int[] TargetsPerQuadrant = { targets / 4, targets / 4, targets / 4, targets / 4 };
            int RemaindingTargets = targets % 4;
            Random rand = new Random();
            while (RemaindingTargets > 0)
            { // Randomly select quadrants to allocate the Remainding targets (one may end up with 3 extra as it is now)
                TargetsPerQuadrant[rand.Next(4)]++;
                RemaindingTargets--;
            }
            PopulateQuadrants(ref matrix, xBeginQuadrant, xEndQuadrant / 2, yBeginQuadrant, yEndQuadrant / 2, TargetsPerQuadrant[0]);
            PopulateQuadrants(ref matrix, xEndQuadrant / 2, xEndQuadrant, yBeginQuadrant, yEndQuadrant / 2, TargetsPerQuadrant[1]);
            PopulateQuadrants(ref matrix, xBeginQuadrant, xEndQuadrant / 2, yBeginQuadrant, yEndQuadrant / 2, TargetsPerQuadrant[2]);
            PopulateQuadrants(ref matrix, xEndQuadrant / 2, xEndQuadrant, yBeginQuadrant / 2, yEndQuadrant, TargetsPerQuadrant[3]);
        }
    }

是否有任何数学上的正确或简单或实现此目的的方法,或者我应该继续这样做。

1 个答案:

答案 0 :(得分:0)

我最终决定在每个角落中随机放置至少四分之一的元素,其余的也随机忽略奇数长度,或者让它向一侧或另一侧倾斜。

private Element[,] GetCancellationTestMatrix(int rows, int columns, int targets, int types)
    {
        // Supposing the different types of elements are just ints and we want a concrete type
        // for our targets which is contained in the variable "TargetType"
        Element[,] Matrix = new int[rows, columns];

        Random rand = new Random();
        int currQuadRowBegin = 0;
        int currQuadRowEnd = rows / 2;

        int currQuadColBegin;
        int currQuadColEnd;

        int rowIndex;
        int colIndex;
        for (int i = 0; i < 2; i++)
        {
            currQuadColBegin = 0;
            currQuadColEnd = columns / 2;
            for (int j = 0; j < 2; j++)
            {
                for (int t = 0; t < targets / 4; t++)
                {
                    rowIndex = rand.Next(currQuadRowBegin, currQuadRowEnd);
                    colIndex = rand.Next(currQuadColBegin, currQuadColEnd);
                    while (Matrix[rowIndex, colIndex] != null)
                    {
                        rowIndex = rand.Next(currQuadRowBegin, currQuadRowEnd);
                        colIndex = rand.Next(currQuadColBegin, currQuadColEnd);
                    }
                    Matrix[rowIndex, colIndex] = new Element(TargetType);
                }
                currQuadColBegin = currQuadColEnd++;
                currQuadColEnd = columns - 1;
            }
            currQuadRowBegin = currQuadRowEnd++;
            currQuadRowEnd = rows - 1;
        }

        // Some targets may be unarranged yet (up to three)
        int remainding = targets % 4;
        while (remainding > 0)
        {
            rowIndex = rand.Next(0, rows);
            colIndex = rand.Next(0, columns);
            while (Matrix[rowIndex, colIndex] != null)
            {
                rowIndex = rand.Next(0, rows);
                colIndex = rand.Next(0, columns);
            }
            Matrix[rowIndex, colIndex] = new Element(TargetType);
            remainding--;
        }

        // Fill the remainding elements of the target matrix with other targets
        List<int> fakeTargets = new List<int>(rows * columns - targets);
        // If we are placing 10 targets in a 9x6 matrix then we need to place an extra 
        // 9 * 6 - 10 = 34 targets and if we have, say, 4 types then we can divide that
        // between 4-1 (for the target type)
        int targetsOfEachType = (rows * columns - targets) / types-1; 
        for (int i = 0; i < types; i++)
        {
            if (i == TargetType) continue;
            for (int j = 0; j < targetsOfEachType; j++)
            {
                fakeTargets.Add(i);
            }
        }
        int tmp;
        while (fakeTargets.Count < rows * columns - targets)
        {
            tmp = rand.Next(types);
            while (tmp == TargetType)
            {
                tmp = rand.Next(types);
            }
            fakeTargets.Add(tmp);
        }
        Shuffle(fakeTargets); // Assume this method shuffles the list of fakeTargets 
        tmp = 0;
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < columns; j++)
            {
                if (Matrix[i, j] != null) continue;
                Matrix[i, j] = new Element(fakeTargets[tmp++]);
            }
        }
        return Matrix;
    }

当然,我并不是说这是一个很好的解决方案,只是至少现在对我有用的解决方案。我会留下一些时间,以便有人可以在我将此作为答案之前发布一个更好的答案或一些更正。