在最后 2 不同的每一行写 0 和 1

Posted

技术标签:

【中文标题】在最后 2 不同的每一行写 0 和 1【英文标题】:write 0's and 1's on each line where the last 2 weren't the same 【发布时间】:2014-06-13 07:43:44 【问题描述】:

我目前构建的逻辑存在错误。 应该发生的是我的代码应该显示一个 0 和 1 的网格。 像这样:

001001
101101
010110
110010
001101

所以这里必须发生的是:

每行连续不能超过 2 个相同类型的数字 号码随机抽取 对于每一列,同一类型的连续数字不能超过 2 个 按列或按行最多可以有 3 个类型的数字

编辑:进一步澄清 好的,所以我有这样的一行: 0 1 0 1 1 0 - 如您所见,总会有 3 x 1 和 3 x 0 - 数字的顺序是随机选择的(所以它可能会从 0 1 或 1 1 或 0 0 开始等) - 同一类型的数字不能连续超过2个,例如001100,你可以看到有2个0,那么它必须显示一个1,但是有2个1,所以它必须显示一个 0。所以 011100 不可​​能发生(连续 3 个 1)或 000101(连续 3 个 0)

基于此,但现在不是必需的,必须在列中连续应用相同的 2 号(所以在我的成功示例中,它跨越 001001,最多连续 2 个 0。但往下看,你会得到 010101(即也就是说,再一次,连续不超过2个)

所以我的代码如下:

    import java.util.Random;

public class Main 

    public static void main(String[] args) 
        int l = 6;
        int w = 6;
        Random rd = new Random();

        // Create a grid that is 6 x 6
        int[][] grid = new int[l][w];
        // for each row
        for (int i = 0; i < l; i++) 
            int zCount = 0;
            int oCount = 0;
            int current;
            int lastA = 2;
            int lastB = 2;
            // for each item in the row
            for (int j = 0; j < w; j++) 
                // set the current item to either 0 or 1
                current = rd.nextInt(2);
                // make sure there aren't already (e.g. 3 items out of 6)
                // items in the row
                if (j % 2 == 1) 
                    // hold every second element
                    lastA = current;
                 else 
                    // hold every first element
                    lastB = current;
                
                if (current == 1) 
                    if (oCount != 3) 
                        if (lastA != lastB) 
                            // if the two previous items aren't the same
                            grid[i][j] = current;
                            // add to the counter
                            oCount++;
                        
                    
                
                if (current == 0) 
                    if (zCount != 3) 
                        if (lastA != lastB) 
                            // if the two previous items aren't the same
                            grid[i][j] = current;
                            // add to the counter
                            zCount++;
                        
                    
                
                System.out.print(grid[i][j]);
            
            System.out.println(" ");
        
    

问题是它生成如下:

010010 
100001 
100010 
000010 
100001 
001000 

显然它不符合第一、第三或第四点。 我完全不知道为什么!除了我没有初始化的列(第三点)。

谁能弄清楚我的代码中的逻辑错误是什么?

感谢您的帮助!

【问题讨论】:

你能更好地解释一下你的规则吗? 您可能无法一次性完成此操作。也就是说,一旦您(随机)选择匹配的第一行,您可能无法选择满足所有 column 约束的后续行。您可能需要一种完全不同的方法。 阐明了规则。此外,目前还不需要列检查,只是让我难过的行检查:/ 按照我在编辑中的建议将“连续”替换为连续。 @DavidG 确实意识到所选答案没有解决最后一个约束?即,“按列或按行,每种类型的数字最多可以有 3 个。” 【参考方案1】:

这是我的程序解决方案,它试图使所需代码的数量尽可能少。它能够计算具有 任意 行和列的二维数组,例如 [6, 6][4, 7] 或 [3, 8] 例如。该算法的复杂度O(n)n = rows * columns

程序计算一个任意二维数组(网格),其中填充了01。网格保证以下特性,用数学公式表示:

r,c ∈ 整数 | 0 ≤ r

r - 2 ≥ 0 ⇒ 基数( distinct( grid[r][c], grid[r-1][c], grid[r-2][c] )) = 2

r + 2

c - 2 ≥ 0 ⇒ 基数( distinct( grid[r][c], grid[r][c-1], grid[r][c-2] )) = 2

c + 2

或者换句话说:

该网格既不包含行也不包含具有三个或更多连续0's1's 的列

在 Java 代码下面,我将解释该算法是如何工作的以及为什么要这样设计:

public static void main(String[] args) 
    int[][] grid = anyGrid(8, 13);


private static int[][] anyGrid(int rows, int cols) 
    int[][] grid = new int[rows][cols];
    int row = 0;
    for (int col = 0; col - row < cols; col++) 
        for (int r = row; r >= 0 && col - r < cols;) 
            setBit(grid, r, col - r--);
        
        if (row < rows - 1) row++;
    
    return grid;


private static void setBit(int[][] grid, int row, int col) 
    int vInd = calcVerticalIndicator(grid, row, col);
    int hInd = calcHorizontalIndicator(grid, row, col);
    if (isPartiallyRestricted(vInd, hInd)) 
        grid[row][col] = flip(vInd);
     else if (isFullyRestricted(vInd, hInd)) 
        grid[row][col] = vInd;
        grid[row - 1][col] = flip(vInd);
     else 
        grid[row][col] = Math.abs(vInd) <= 1
                ? flip(vInd)
                : Math.abs(hInd) <= 1 ? flip(hInd) : anyBit();
    


private static boolean isPartiallyRestricted(int vInd, int hInd) 
    return vInd == hInd;


private static boolean isFullyRestricted(int vInd, int hInd) 
    return vInd + hInd == 1;


private static int calcVerticalIndicator(int[][] grid, int row, int col) 
    return calcIndicator(grid, row - 1, col, row - 2, col, 2);


private static int calcHorizontalIndicator(int[][] grid, int row, int col) 
    return calcIndicator(grid, row, col - 1, row, col - 2, 4);


private static int calcIndicator(int[][] grid, int row1, int col1, int row2, int col2, int unrestricted) 
    try 
        return grid[row1][col1] * grid[row2][col2] + (grid[row1][col1] - grid[row2][col2]) * unrestricted;
     catch (IndexOutOfBoundsException e) 
        return unrestricted;
    


private static int anyBit() 
    return (int) (Math.random() * 2);


private static int flip(int bit) 
    return bit == 0 ? 1 : 0;

我们面临的挑战不是确保没有三个连续的0's1's 在一行或一列中。挑战在于通过提供一种有效的算法来确保没有三个连续的0's1's 既不在行中也不在列中。

我们可能遇到的棘手情况如下:

让我们考虑这样一种情况,即所有位于蓝色轮廓单元格顶部和左侧的单元格都已填充且不违反上面定义的规则。

图片 a)我们想要填充具有蓝色轮廓的单元格。它顶部的两个单元格填充了两个0's,而左侧的单元格填充了两个1's。我们应该选择哪个值?由于对称性,我们选择01 并不重要。因此,让我们使用0

图片 b)用 0 填充蓝色轮廓的单元格违反了上面定义的一条规则:网格不包含具有三个或更多连续 @987654338 的列@ 或 1's。因此,我们必须更改蓝色单元格上方两个单元格之一的值。

图片 c)说我们将蓝色单元格正上方的单元格的值从 0 更改为 1。这可能会导致违反某些规则,这是由已修改单元格左侧的已填充单元格引起的。

图片 d),但违规意味着左侧的两个单元格的值必须为 1

图片 e)这意味着它们顶部的两个单元格必须具有 0 的值,这与我们假设的情况相矛盾。因此,立即更改蓝框单元格顶部的单元格不会导致任何违反规则的行为。

为了解决前提条件,即修改后的单元格右侧没有已填充的单元格,该算法以对角线方式填充网格。细胞群的出现顺序如下:

我想解释的最后一件事是算法如何决定每个单元格可以选择哪些值。对于每个单元格,它检查最顶部的两个单元格和最左侧的两个单元格并计算指示值。该值用于通过以下算术计算确定单元格的可能值:

如果检查的两个单元格都使用0's 填充,则返回指示值0

如果检查的两个单元格都填充了1's,则返回指示值1

我选择这两个值是因为它们以直观的方式传达了一个事实,即不允许使用这些值。

然后我选择了一个函数来进行通信,如果列单元格和行单元格都限制单元格填充相同的值。如果两个指标值相等,就会出现这种情况。请牢记这一特性,因为我们必须为列单元格或行单元格不受限制的情况找到值。

如果两个指标都限制值以不同的值填充单元格,则它们的总和为 1。这是我们在没有限制的情况下搜索合适的指标值时必须牢记的第二个特征。

算法必须实现的最后一件事是在不影响上面定义的唯一指标的情况下,在没有限制的情况下找到合适的值。

通过选择不同于01的行和列指示符的值,可以实现在单元格被相同值限制时保留指示> 并且彼此不同。

通过选择大于 1 且彼此之间的增量至少为 2 的值,可以在单元格受两个值限制时保留指示强>.

该算法确实通过值 2-2 指示对行没有限制,通过值 4 和 -4。此值与用于识别其他两种情况的操作不冲突。

我希望本文档有助于理解整个程序以及它如何解决问题陈述。我很高兴听到你的 cmets。

【讨论】:

+1 表示努力和解释的清晰 您缺少一条规则:“按列或按行最多可以有 3 个每种类型的数字”。换句话说,如果它是一个 6x6 的网格,那么所有行和所有列都必须正好包含 3 个 0 和 3 个 1。 不幸的是,这确实违反了最终规则,否则这是一个很棒的解决方案。有没有办法纠正这个问题? 我花了更多时间分析冲突情况,但对我来说,避免创建无冲突但仍然最大的随机矩阵似乎很复杂。因此,到目前为止我看到的选项是策略 a) 试图通过将某些值限制为01 来防止冲突情况,同时填充矩阵,即使其他值是可能的.或者策略 b) 用随机值填充矩阵,直到冲突无法解决,然后重新开始整个矩阵填充(理论上可能导致无限循环)。 您是否有兴趣修改我的代码以解决策略 a) 或策略 b)【参考方案2】:

给出的许多解决方案都非常冗长和复杂。这是一个代码非常少的解决方案 (Ideone Example here):

int row, col, n = 8;
int[][] grid = new int[n][n], cCount = new int[n][2], rCount = new int[n][2];
Deque<Entry<Integer,Integer>> freeInd = new ArrayDeque<Entry<Integer,Integer>>();
Random rand=new Random();
for(int i = 0; i < grid.length; i++)
    for(int j = 0; j < grid[0].length; j++)
        // Calcualte constraints: row, col = -1, 0, 1,  -1 => no constraint.
        row = j > 1 && grid[i][j-2] == grid[i][j-1] ? (grid[i][j-1] == 0 ? 1:0):  
             (rCount[i][0] >= n/2 ? 1:                           // too many 0's
             (rCount[i][1] >= n/2 ? 0:-1));                      // too many 1's
        col = i > 1 && grid[i-2][j] == grid[i-1][j] ? (grid[i-1][j] == 0 ? 1:0):
             (cCount[j][0] >= n/2 ? 1:                           // too many 0's
             (cCount[j][1] >= n/2 ? 0:-1));                      // too many 1's
        grid[i][j] = row == -1 && col == -1 ? rand.nextInt(2):(row > -1 ? row:col);

        // Handle Constraints
        if( row == -1 && col == -1)                              // no constraint
            freeInd.push(new SimpleEntry<Integer,Integer>(i, j)); // add to free indices
         else if( (row > -1 && col > -1 && row != col)           // constraint conflict
                || (row > -1 && rCount[i][row] >= n/2)            // count conflict
                || (col > -1 && cCount[j][col] >= n/2))          // count conflict
            Entry<Integer, Integer> last = freeInd.pop();         // grab last free index
            while(i > last.getKey() || j > last.getValue())
                j = (j-1+ n)%n;                                   // step indices back
                i = (j == n-1) ? i-1:i;   
                rCount[i][grid[i][j]]--;                          // reduce counters
                cCount[j][grid[i][j]]--;
            
            grid[i][j] = grid[i][j] == 0 ? 1:0;                   // flip value
               
        rCount[i][grid[i][j]]++;                                  // increment counters
        cCount[j][grid[i][j]]++;
    

这里的想法是你沿着矩阵的每一行添加 0 和 1,遵守以下规则:

    如果当前索引不受约束(即它可以是 0 或 1),我们会随机选择一个值。 如果当前索引受到约束,我们会强制它具有约束值。 如果存在多个不一致的约束,我们首先沿矩阵的行逐步向后退,减少给定值(0 或 1)的计数,从而恢复到最后一个无约束索引 (freeInd) .例如。这是针对带有rCount[i][grid[i][j]]-- 的行完成的。当最终到达不受约束的顶点时,翻转它的值。 最后,增加当前行和列的值(0 或 1)的计数。例如。这是针对带有rCount[i][grid[i][j]]++ 的行完成的

【讨论】:

唯一的问题是它违反了规则“每列或行最多可以有3个类型的数字” 确实如此,但可以很容易地添加。有时间我会补充的。 @DavidG 好的添加了它 不错,这里有一些很棒的东西,但如此紧凑是我的理想答案。谢谢:) @Jason,感谢您的鼓励;我已经添加了您的回溯建议。此外,将其推广到处理任何网格大小 nxn。【参考方案3】:

我在您的解决方案中发现的第一个问题是将计数器值(ocount 和 zcount)的值初始化为零,并且为 grid(array) 分配值的唯一方法是当它大于三时,以及方式我看看我是否记错了 counter 的值在检查它们是否大于 3 的循环中递增,并且永远无法达到该条件。 为了解决这个问题,使用回溯算法,将新值分配给不同的值,如果计算得到

【讨论】:

你说得对,谢谢你的分析,现在回头看看我搞砸了谁【参考方案4】:

jsFiddle 中的工作代码(适用于 6x6 网格):

$(function()
    function print(str)
        $("body").append(str + "<br/>");
    

    function toBin(num, length)
        if(!length)
            length = 3;
        
        var str = num.toString(2);
        while(str.length < length)
            str = 0 + str;
        
        return str;
    


    var wrongAnds = [
        parseInt('000000111', 2),
        parseInt('000111000', 2),
        parseInt('111000000', 2),
        parseInt('100100100', 2),
        parseInt('010010010', 2),
        parseInt('001001001', 2),
                   ];

    var wrongOrs = [
        parseInt('111111000', 2),
        parseInt('111000111', 2),
        parseInt('000111111', 2),
        parseInt('011011011', 2),
        parseInt('101101101', 2),
        parseInt('110110110', 2),
                   ];

    function test(mask)
        for (var i = 0; i < 6; i++) 
            if((wrongAnds[i] & mask) == wrongAnds[i])
                return false;
            
            if((wrongOrs[i] | mask) == wrongOrs[i])
                return false;
            
        
        return true;
    

    var threeGrid = [];

    var toRight = [];
    var toBottom = [];

    for(var mask = 1<<9-1; mask >= 0; mask--)
        if(test(mask))
            threeGrid.push(mask);
        
    

    function numberOfSetBits(i)
    
         i = i - ((i >> 1) & 0x55555555);
         i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
         return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    

    function getCol(grid, col)
        var ret = 0;
        for(var i=0; i<3; i++)
            ret += (grid & (1 << (i*3+col))) >> (i*2+col);
        
        return ret;
    

    var wrongAnds6 = [
        parseInt('011100', 2),
        parseInt('001110', 2)
                   ];
    var wrongOrs6 = [
        parseInt('100011', 2),
        parseInt('110001', 2)
                   ];

    for(var i = 0; i < threeGrid.length; i++)
        for(var j = 0; j < threeGrid.length; j++)
            var grid1 = threeGrid[i];
            var grid2 = threeGrid[j];
            var toRightOk = true;
            var toBottomOk = true;
            var printit = (i==0);
            for(var k=0;k<3;k++)
                var row = ((grid1 & wrongAnds[k]) << 3 >> (k*3)) + ((grid2 & wrongAnds[k]) >> (k*3));
                var col = ((getCol(grid1, k)) << 3) + ((getCol(grid2, k)));

                if(numberOfSetBits(row) != 3 
                   || ((wrongAnds6[0] & row) == wrongAnds6[0])
                   || ((wrongAnds6[1] & row) == wrongAnds6[1])
                   || ((wrongOrs6[0] | row) == wrongOrs6[0])
                   || ((wrongOrs6[1] | row) == wrongOrs6[1])
                  ) 
                    toRightOk = false;
                
                if(numberOfSetBits(col) != 3 
                   || ((wrongAnds6[0] & col) == wrongAnds6[0])
                   || ((wrongAnds6[1] & col) == wrongAnds6[1])
                   || ((wrongOrs6[0] | col) == wrongOrs6[0])
                   || ((wrongOrs6[1] | col) == wrongOrs6[1])
                  ) 
                    toBottomOk = false;
                

            

            if(toRightOk)
                if(!toRight[grid1])
                    toRight[grid1] = [];
                
                    toRight[grid1].push(grid2);
            
            if(toBottomOk)
                if(!toBottom[grid1])
                    toBottom[grid1] = [];
                
                toBottom[grid1].push(grid2);
            
        
    

    function intersect(arr1, arr2)
        var results = [];

        for (var i = 0; i < arr1.length; i++) 
            if (arr2.indexOf(arr1[i]) !== -1) 
                results.push(arr1[i]);
            
        
        return results;
    

    var found = false;
    while(!found)
        var grid1 = threeGrid[0];
        var grid1 = threeGrid[Math.floor(Math.random()*threeGrid.length)];
        var grid2 = toRight[grid1][Math.floor(Math.random()*toRight[grid1].length)];
        var grid3 = toBottom[grid1][Math.floor(Math.random()*toBottom[grid1].length)];
        var arr4 = intersect(toBottom[grid2], toRight[grid3]);
        if(arr4.length > 0)
            var grid4 = arr4[Math.floor(Math.random()*arr4.length)];
            found = true;
        
    

    function gridToStrings(grid)
        var rowS = [];
        for(var i=0; i<3; i++)
            rowS.push(toBin(((grid & wrongAnds[i]) >> (i*3))));
        
        return rowS;
    

    var grid1S = gridToStrings(grid1);
    var grid2S = gridToStrings(grid2);
    var grid3S = gridToStrings(grid3);
    var grid4S = gridToStrings(grid4);

    print(grid1S[0] + grid2S[0]);
    print(grid1S[1] + grid2S[1]);
    print(grid1S[2] + grid2S[2]);
    print(grid3S[0] + grid4S[0]);
    print(grid3S[1] + grid4S[1]);
    print(grid3S[2] + grid4S[2]);

);

理论:

    找到所有可能的 3x3 网格 找到所有可能的从左到右和从上到下的配对 获取 4 个随机网格以形成 6x6 网格

实施:

    将 3x3 网格表示为 9 位整数。如果其中有 3 个 1 或 3 个 0,则 3x3 网格是错误的。这可以通过几个按位运算轻松过滤。 测试这些 3x3 网格的笛卡尔积(将每个网格与每个网格进行比较)。检查所有行和列中是否正好有 3 个 0 和 3 个 1(将第二个网格放在第一个网格的右边检查 3 行,并将其放在第一个网格下方检查 3 列),并且没有连续的 3 0 或 1。 获取左上角、右上角和右下角的网格。检查是否有可用的第 4 个网格可以位于右上网格下方并从右到左下网格。如果没有,请重新开始第 4 步,否则选择一个。

几个输出:

011010
100101
001011
110100
101100
010011

110010
101100
010011
001101
100110
011001

001101
110010
010011
101100
110100
001011

编辑: 这个问题只有 1120 个解决方案 (jsFiddle)。有 2^36 种方法可以用 0 和 1 填充 6x6 网格。如果你使用蛮力(获得一个随机的 6x6 网格,然后检查它是否正确),这意味着平均 ~61356676 (6.1*10^7) 次执行来找到正确的解决方案。即使您的方法更快一些(如果不是最后一个数字错误,它可能会更快失败),它可能仍然很慢。

【讨论】:

这是在 javascript 中而不是在 java 中,但仍然非常有趣。是否有一种方法可以调整它以使其适合 9x9 网格?或者每次使用变量(7x7、8x8 网格等)更改网格? @DavidG 问题指出:“每种类型的数字最多可以有 3 个按列或按行排列”。如果我们将该条件更改为“每行和每列必须包含相同数量的 1 和 0”,则可以,尽管位掩码最多仅适用于 64 位(8*8 网格),在此之上,您必须使用布尔数组。对于 8*8 计算所有 4*4 网格,然后所有 8*8 网格可能会起作用,对于更高的维度,最好分多个步骤计算最终网格(例如:首先是所有可能的 3*3,然后是所有 6*6从那开始,然后是所有 12*12)。【参考方案5】:

我认为你的代码有两个问题:

如果 oCountzCount 已变为 3,则如果随机值不可接受,则不会再分配 grid[i][j]=current。您在这些位置(网格被初始化到的位置)处得到零。

在右下角附近可能没有任何更有效的解决方案。您必须撤消之前的分配,即您需要进行某种回溯。

我建议从一个有效的解决方案开始,并根据网格位置的随机值逐步转换此解决方案 - 但前提是在不破坏有效性的情况下这是可能的。如果已经准备了一个示例实现:

public static void main(String[] args) 
    int l = 6, w = 6;
    Grid g = new Grid(l, w);
    Random rd = new Random();

    // initialize with checkerboard pattern (which is a valid solution)
    for (int y = 0; y < l; y++) for (int x = 0; x < w; x++) g.arr[y][x] = (x ^ y) & 1;

    // construct a valid grid by transformation of grids while preserving validity
    for (int y = 0; y < l; y++) for (int x = 0; x < w; x++) 
        int v = rd.nextInt(2), v2 = v ^ 1;
        if (g.arr[y][x] == v) continue;

        // try to modify current grid by exchanging values: 01/10=>10/01 or 10/01=>01/10
        // (keep parts of the grid which have already been adapted to random values)
        rotating: for (int y2 = y + 1; y2 < l; y2++) for (int x2 = x; x2 < w; x2++) 
            if (g.arr[y2][x] == v && g.arr[y][x2] == v && g.arr[y2][x2] == v2) 
                g.rotate(x, y, x2, y2);
                // keep result if grid is still valid, undo otherwise 
                if (g.rotatedOk(x, y, x2, y2)) break rotating;
                g.rotate(x, y, x2, y2);
            
        
    
    g.printOn(System.out);


public static class Grid 
    int l, w;
    int[][] arr;
    Grid(int l, int w) 
        this.arr = new int[this.l = l][this.w = w];
    
    void rotate(int x, int y, int x2, int y2) 
        int v;
        v = arr[y][x]; arr[y][x] = arr[y2][x]; arr[y2][x] = v;
        v = arr[y][x2]; arr[y][x2] = arr[y2][x2]; arr[y2][x2] = v;
    
    boolean rotatedOk(int x, int y, int x2, int y2)  // check after rotation
        return okAt(x, y) && okAt(x2, y) && okAt(x, y2) && okAt(x2, y2);
    
    private boolean okAt(int x, int y)  // check single position in grid
        int v = arr[y][x];
        if (count(x, y, -1, 0, v) + count(x, y, 1, 0, v) > 1) return false;
        if (count(x, y, 0, -1, v) + count(x, y, 0, 1, v) > 1) return false;
        return true;
    
    private int count(int x, int y, int dx, int dy, int v) 
        for (int n = 0; ; n++)  
            x += dx; y += dy; 
            if (x < 0 || x >= w || y < 0 || y >= l || arr[y][x] != v) return n;
        
    
    void printOn(PrintStream s) 
        for (int y = 0; y < l; y++)  for (int x = 0; x < w; x++) s.print(arr[y][x]); s.println(); 
    

【讨论】:

【参考方案6】:

您的方法的问题在于,您需要一种机制来处理无法使用新值的情况,因为它遵循两个相似的值,但另一个值不能使用,因为它在其他两个值之下。例如,假设您的网格已经走到了这一步:

101010
011010
00?

然后您需要慢慢回滚位置并尝试不同的值。

以下代码使用递归解决了这个问题:

import java.util.Random;

public class Main 

    final int height = 6;
    final int width = 6;
    int[][] grid;
    Random rd = new Random();


    public static void main(final String[] args) 
        Main main = new Main();
        main.process();
    


    private void process() 
        // Create a grid that is 6 x 6
        grid = new int[height][width];
        for(int x = 0; x < width; x++) 
            for(int y = 0; y < height; y++) 
                grid[x][y] = -1;
            
        

        recurseFillMatrix(0, 0);
    


    private boolean recurseFillMatrix(final int x, final int y) 

        // first, try putting a random number in the cell
        int attempt = 1;
        grid[x][y] = Math.abs(rd.nextInt()%2);

        do 
            if(isGridValid()) 
                if(x == (width - 1) && y == (height - 1)) 
                    printGrid();
                    return true;
                

                boolean problemSolved;
                if(x == (width - 1)) 
                    problemSolved = recurseFillMatrix(0, y + 1);
                 else 
                    problemSolved = recurseFillMatrix(x + 1, y);
                
                if(problemSolved) 
                    return true;
                
            
            attempt++;
            grid[x][y] = 1 - grid[x][y];
         while(attempt <= 2);

        grid[x][y] = -1;
        return false;
    


    private boolean isGridValid() 
        for(int y = 0; y < height; y++) 
            for(int x = 0; x < width; x++) 
                // if the current item is -1, then we are finished
                if(grid[x][y] == -1) 
                    return true;
                

                // if we are after the second column
                if(x > 1) 
                    if(grid[x-2][y] == grid[x-1][y] && grid[x-1][y] == grid[x][y]) 
                        return false;
                    
                

                // if we are after the second row
                if(y > 1) 
                    if(grid[x][y-2] == grid[x][y-1] && grid[x][y-1] == grid[x][y]) 
                        return false;
                    
                

                // total the values in this column
                int total = 0;
                for(int i = 0; i <= y; i++) 
                    total += grid[x][i];
                
                if(y == (height - 1)) 
                    if(total != 3) 
                        return false;
                    
                 else 
                    if(total > 3) 
                        return false;
                    
                

                // total the values in this row
                total = 0;
                for(int i = 0; i <= x; i++) 
                    total += grid[i][y];
                
                if(x == (width - 1)) 
                    if(total != 3) 
                        return false;
                    
                 else 
                    if(total > 3) 
                        return false;
                    
                
            
        

        return true;
    


    private void printGrid() 
        for(int y = 0; y < height; y++) 
            for(int x = 0; x < width; x++) 
                System.out.print(grid[x][y]);
            
            System.out.println("");
        
    


isGridValid() 方法使用您定义的规则来检查网格(到目前为止已填充)是否符合规则。在第一个表明它不存在的迹象时,它返回 false。

【讨论】:

【参考方案7】:

如果我必须更改您的解决方案以达到结果,它应该是这样的......

    在单独的 if-else 中获取 oCount 和 zCount 的增量器 在循环外给 grid(i,j) 赋值 您的 if-else 块没有考虑所有可能的条件,例如
      如果最后 2 项相同,该怎么办 zCount 或 oCount 达到 3 时会怎样

考虑到这些因素,这段代码运行良好。

import java.util.Random;

public class Main 

public static void main(String[] args) 
    int l = 6;
    int w = 6;
    Random rd = new Random();

    // Create a grid that is 6 x 6
    int[][] grid = new int[l][w];
    // for each row
    for (int i = 0; i < l; i++) 
        int zCount = 0;
        int oCount = 0;
        int current;
        int lastA = 2;
        int lastB = 2;
        // for each item in the row
        for (int j = 0; j < w; j++) 
            // set the current item to either 0 or 1
            current = rd.nextInt(2);
            // make sure there aren't already (e.g. 3 items out of 6)
            // items in the row



            if (current == 1) 
                if (oCount != 3) 
                    if (lastA == lastB) 
                        current = lastA == 1 ? 0 : 1;
                    
                 else 
                    current = current == 1 ? 0 : 1;
                
             else if (current == 0) 
                if (zCount != 3) 
                    if (lastA == lastB) 
                        current = lastA == 1 ? 0 : 1;
                    
                 else 
                    current = current == 1 ? 0 : 1;
                
            

            grid[i][j] = current;

            if (current == 1) 
                oCount++;
             else 
                zCount++;
            

            if (j % 2 == 1) 
                // hold every second element
                lastA = current;
             else 
                // hold every first element
                lastB = current;
            

            System.out.print(grid[i][j]);
        
        System.out.println(" ");
    


同样,此解决方案仅处理行条件。您还需要对列进行类似的检查,以获得完整的结果

HTH

【讨论】:

【参考方案8】:

这里我测试了你的问题,似乎是你需要的。

我使用 Guava 的函数式方法,它非常简单、可读且代码短。

    @Test
    public void test_permutations()
    
        List<Integer> binary = Lists.newArrayList(1,0,1,0,1,0); // Domain list
        Set<String> flattenSet = Sets.newHashSet(); // Store non-repetitive values

        // Create list of possible values
        Collection<List<Integer>> permutations = Collections2.permutations(binary);
        for (List<Integer> permutation : permutations)
        
            String joinString = StringUtils.join(permutation, "");
            flattenSet.add(joinString);
        

        // Create predicate to filter positive values
        Predicate<String> predicate = new Predicate<String>() 
            public boolean apply(String input) 
                // Discard wrong values
                if (input.contains("000") || input.contains("111")) 
                    return false;
                 else 
                    return true;
                
            
        ;

        // Use predicate to filter values
        Collection<String> filteredList = Collections2.filter(flattenSet, predicate);

        // Display result
        for (String result : filteredList) 
            System.out.println(result);
        

    

很简单,我把代码注释清楚了,但你可以调试它来一步步理解。

生成的输出是:

010011
110010
010101
010110
100110
101001
011010
110100
001011
001101
011001
101010
101100
100101

希望能帮到你

【讨论】:

您的解决方案不会阻止同一列中出现 3 个或更多连续的 0 或 1。查看第 2 列和第 1 - 4 行。同一列中有四个 1,这是不允许的。 @Harmlezz 谢谢你指点我,没注意到。【参考方案9】:

我认为一次生成一个元素是错误的。而是想象我生成了整组允许的行 001100,101010,....etc 只有 6!/(3!3!)=20 种排列三个和三个的方法,其中一些将被排除在外.现在我要生成一个博弈树,说一个动作是为下一行选择一个有效的行。如果我在某个时候发现没有更多有效的移动,那么我会回溯并尝试不同的移动。

为了生成一个移动,我随机选择一行,如果它是一个有效的移动,我尝试选择另一个移动,如果这不可能,我回溯,有效地对游戏树进行(随机)深度优先搜索。

public class gametree 

    public static ImmutableList<Row> allValidRows = // create a list of all valid rows.

    public static List<Rows> getValidMoves(Move parent) //Backtracks up the 
    //tree to the root to find the current state of the board, and returns
     //which ever of allValidRows are valid given the game board.
    



    public class Move 
        public final Move parent;
        public List<Rows> validMoves;
        public final Row thisMove;
        public int depth=0;

        Move(Move parent, Row thisMove)
            this.thisMove = thisMove;
            this.parent = parent;
            this.validMoves = getValidMoves(parent);
            Move hold=parent;
            while(hold!=null)
                 depth++; hold = parent.parent;
            
        
    

    void run 
         //pick first move
         Move Root = new Move(null, Collections.Shuffle(allValidRows).get(0));
         Move FinalMove = search(Root); 
         //Something to print out the answer here

    


    public Move search(Move move)
         if(depth==5) return Move //If I get to row six I win.
         else if(move.validMoves.isEmpty())  //If there are no valid moves, 
              //then this move wasnt valid, to strip it from the parent's 
              //possible moves and try again
               move.parent.validMoves.remove(move.thisMove);
               search(move.parent);
          else  //pick a random valid move and create a nextMove
             Move nextMove = new Move(move, Collection.Shuffle(move.getValidMoves).get(0))
             search(nextMove);
         


这个算法最坏的情况是只有一个胜利状态,它必须尝试每一个可能的状态,但实际上这个游戏似乎没有太多限制,所以可能根本不会花很长时间。

此代码仅用于说明。

【讨论】:

以上是关于在最后 2 不同的每一行写 0 和 1的主要内容,如果未能解决你的问题,请参考以下文章

上台阶

上台阶

3525:上台阶

Matlab中的左循环移位,用于不同数量位置的矩阵的每一行

如何在R中的不同表中找到相等的行?

递推-练习2--noi3525:上台阶