将元素排列成任意大小的矩阵

Arrange elements in a matrix of any size

这与其说是问题本身,不如说是讨论,因为我可以用代码解决这个问题,但我认为应该有更好的方法来解决这个问题。

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

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

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

我首先想到的是用一个递归函数来处理这个问题,该函数划分为象限并随机放置每个元素。

我已经用 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]);
        }
    }

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

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

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;
    }

当然,我并不是说这是一个好的解决方案,只是说至少目前对我有用。我会留出一些时间,以便有人可以 post 在我将其作为答案之前 post 提出更好的答案或进行一些更正。