java 数组递归

发布于 2024-08-29 21:20:09 字数 1674 浏览 1 评论 0原文

我必须创建一个程序来找到用 y 填充 x 大小的正方形的所有可能方法。您放置一个占据 2 个空间的方块来完全填满。

问题是我不知道如何编码才能记住每个方块的位置。我可以让它完全填满棋盘一次,也许两次,但不能超过那个。我也知道我应该使用递归来解决这个问题。这是到目前为止我开始编写的代码。还有一个主要方法,我的初始偶/奇检查工作正常。这是我不知道的部分。

    public void recurDomino(int row, int column) {
            if (Board[2][x - 1] != false) {

            } else if(Board[1][x-1]!=false)
            {

            }
            else {
                for (int n=0; n < x - 1; n++) {
                    Board[row][column] = true;
                    Board[row][column+1] = true;
                    column++;
                    counter++;
                } 
                recurDomino(1, 0);
                recurDomino(2, 0);

            }
        }

Thank you for any help you guys can give me. 


******************* EDIT ****************************************

我还是有点困惑。我想出了这个算法,但对于任何大于或等于 2 的值,我总是得到 2。

public boolean tryHorizontal(int row , int col){
        if( row < 0 || row >= array[0].length-1)
            return false;
        else
            return true;
    }

    public boolean tryVertical(int row, int col){
        if( col < 0 || col >= 2 )
            return false;
        else
            return true;
    }

    public boolean tryRowCol(int row, int col){
        if(this.tryHorizontal(row, col) && this.tryVertical(row, col)){
            return true;
        }
        else
            return false;
    }

    public int findWays(int row, int col){
        int n = 0;
        if( !this.tryRowCol(row, col))
            return 0;
        else
            n =+ 1 + this.findWays(row+1, col+1);

        return n;
    }

I have to create a program that finds all the possible ways of filling a square of size x by y. You place a block which takes up 2 spaces to completely fill.

The problem is I don't know how to code it to the point where you can remember the placements of each square. I can get it to where it fills the board completely once and maybe twice, but nothing past that. I also know that I'm supposed to use recursion to figure this out . Here is the code I started on so far. There is also a main method and I have the initial even/odd check working fine. This is the part I have no idea on.

    public void recurDomino(int row, int column) {
            if (Board[2][x - 1] != false) {

            } else if(Board[1][x-1]!=false)
            {

            }
            else {
                for (int n=0; n < x - 1; n++) {
                    Board[row][column] = true;
                    Board[row][column+1] = true;
                    column++;
                    counter++;
                } 
                recurDomino(1, 0);
                recurDomino(2, 0);

            }
        }

Thank you for any help you guys can give me. 


******************* EDIT ****************************************

I am a little confused still. I came up with this algorithm but I always get 2 for any value greater or equal to 2.

public boolean tryHorizontal(int row , int col){
        if( row < 0 || row >= array[0].length-1)
            return false;
        else
            return true;
    }

    public boolean tryVertical(int row, int col){
        if( col < 0 || col >= 2 )
            return false;
        else
            return true;
    }

    public boolean tryRowCol(int row, int col){
        if(this.tryHorizontal(row, col) && this.tryVertical(row, col)){
            return true;
        }
        else
            return false;
    }

    public int findWays(int row, int col){
        int n = 0;
        if( !this.tryRowCol(row, col))
            return 0;
        else
            n =+ 1 + this.findWays(row+1, col+1);

        return n;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

同展鸳鸯锦 2024-09-05 21:20:09

这种递归解决方案实际上生成通用MxN板的所有可能的平铺。它比您的程序所需的更通用,因此没有优化为仅计数 3xN 板的平铺数量。

如果您只想计算有多少个,可以使用动态编程技术并且执行此操作更快。此外,将行数固定为 3 实际上使问题变得容易得多。尽管如此,这种通用的生成解决方案应该具有指导意义。

public class Domino {
    final int N;
    final int M;
    final char[][] board;
    int count;

    static final char EMPTY = 0;

    Domino(int M, int N) {
        this.M = M;
        this.N = N;
        board = new char[M][N]; // all EMPTY
        this.count = 0;
        generate(0, 0);
        System.out.println(count);
    }

    void printBoard() {
        String result = "";
        for (char[] row : board) {
            result += new String(row) + "\n";
        }
        System.out.println(result);     
    }

    void generate(int r, int c) {
       //... see next code block
    }
    public static void main(String[] args) {
        new Domino(6, 6);
    }
}

重点是:

    void generate(int r, int c) {
        // find next empty spot in column-major order
        while (c < N && board[r][c] != EMPTY) {
            if (++r == M) {
                r = 0;
                c++;
            }
        }
        if (c == N) { // we're done!
            count++;
            printBoard();
            return;
        }
        if (c < N - 1) {
            board[r][c] = '<';
            board[r][c+1] = '>';
            generate(r, c);
            board[r][c] = EMPTY;
            board[r][c+1] = EMPTY;
        }
        if (r < M - 1 && board[r+1][c] == EMPTY) {
            board[r][c] = 'A';
            board[r+1][c] = 'V';
            generate(r, c);
            board[r][c] = EMPTY;
            board[r+1][c] = EMPTY;
        }
    }

输出最后几行的摘录给出了生成的棋盘和最终计数的示例。

//... omitted

AA<><>
VVAA<>
AAVV<>
VVAA<>
<>VVAA
<><>VV

//... omitted

6728

请注意,6728 使用 OEIS A004003 进行检查。

您需要从此解决方案中学习的一些内容是:

  • 自行清理!这是修改可变共享数据的递归解决方案中非常常见的模式。您可以随意做的事情,但将事情保留在您发现的地方,以便其他人可以做他们的事情。
  • 找出探索搜索空间的系统方法。在这种情况下,多米诺骨牌被放置在 列主顺序,以其左上角为参考点。

所以希望你能从中学到一些东西,并根据你的作业调整这些技巧。祝你好运!


提示:如果注释掉 printBoard 行,您可以在合理的时间内生成 8x8 的所有约 1300 万个板。不过,只计算数字肯定会快得多,而不必一一生成和计算它们。


更新!

这是 3xN 板的递归生成器。它不使用共享可变数组,而只是使用不可变字符串。它使逻辑更简单(无需清理,因为您没有弄乱!)并且代码更具可读性(各个部分的放置位置和方式都是可见的!)。

由于我们固定为 3 行,因此如果我们只有 3 个相互递归函数,逻辑会更加明确。

public class Domino3xN {
   static int count = 0;

   public static void main(String[] args) {
      addRow1(8, "", "", "");
      System.out.println(count);
   }

   static void addRow1(int N, String row1, String row2, String row3) {
      if (row1.length() == N && row2.length() == N && row3.length() == N) {
         count++; // found one!
         System.out.format("%s%n%s%n%s%n%n", row1, row2, row3);
         return;
      }
      if (row1.length() > row2.length()) { // not my turn!
         addRow2(N, row1, row2, row3);
         return;
      }
      if (row1.length() < N - 1)
         addRow2(N, row1 + "<>",
                    row2,
                    row3);
      if (row2.length() == row1.length())
         addRow3(N, row1 + "A",
                    row2 + "V",
                    row3);
   }
   static void addRow2(int N, String row1, String row2, String row3) {
      if (row2.length() > row3.length()) { // not my turn!
         addRow3(N, row1, row2, row3);
         return;
      }
      if (row2.length() < N - 1)
         addRow3(N, row1,
                    row2 + "<>",
                    row3);
      if (row3.length() == row2.length())
         addRow1(N, row1,
                    row2 + "A",
                    row3 + "V");
   }
   static void addRow3(int N, String row1, String row2, String row3) {
      if (row3.length() == row2.length()) { // not my turn!
         addRow1(N, row1, row2, row3);
         return;
      }
      if (row3.length() < N - 1)
         addRow1(N, row1,
                    row2,
                    row3 + "<>");
   }
}

您不会经常看到像这样的 3 个相互递归函数,因此这应该具有教育意义。

This recursive solution actually generates all the possible tiling of a general MxN board. It's more general than what your program requires, and therefore not optimized to just count the number of tiling of a 3xN board.

If you just want to count how many there are, you can use dynamic programming techniques and do this much faster. Also, having the number of rows fixed at 3 actually makes the problem considerably easier. Nonetheless, this general generative solution should be instructive.

public class Domino {
    final int N;
    final int M;
    final char[][] board;
    int count;

    static final char EMPTY = 0;

    Domino(int M, int N) {
        this.M = M;
        this.N = N;
        board = new char[M][N]; // all EMPTY
        this.count = 0;
        generate(0, 0);
        System.out.println(count);
    }

    void printBoard() {
        String result = "";
        for (char[] row : board) {
            result += new String(row) + "\n";
        }
        System.out.println(result);     
    }

    void generate(int r, int c) {
       //... see next code block
    }
    public static void main(String[] args) {
        new Domino(6, 6);
    }
}

So here's the meat and potatoes:

    void generate(int r, int c) {
        // find next empty spot in column-major order
        while (c < N && board[r][c] != EMPTY) {
            if (++r == M) {
                r = 0;
                c++;
            }
        }
        if (c == N) { // we're done!
            count++;
            printBoard();
            return;
        }
        if (c < N - 1) {
            board[r][c] = '<';
            board[r][c+1] = '>';
            generate(r, c);
            board[r][c] = EMPTY;
            board[r][c+1] = EMPTY;
        }
        if (r < M - 1 && board[r+1][c] == EMPTY) {
            board[r][c] = 'A';
            board[r+1][c] = 'V';
            generate(r, c);
            board[r][c] = EMPTY;
            board[r+1][c] = EMPTY;
        }
    }

This excerpt from the last few lines of the output gives an example of a generated board, and the final count.

//... omitted

AA<><>
VVAA<>
AAVV<>
VVAA<>
<>VVAA
<><>VV

//... omitted

6728

Note that 6728 checks out with OEIS A004003.

A few things that you need to learn from this solutions are:

  • Clean-up after yourself! This is a very common pattern in recursive solution that modifies a mutable shared data. Feel free to do your thing, but then leave things as you found them, so others can do their thing.
  • Figure out a systematic way to explore the search space. In this case, dominoes are placed in column-major order, with its top-left corner as the reference point.

So hopefully you can learn something from this and adapt the techniques for your homework. Good luck!


Tip: if you comment out the printBoard line, you can generate all ~13 million boards for 8x8 in reasonable time. It'll definitely be much faster to just compute the number without having to generate and count them one by one, though.


Update!

Here's a recursive generator for 3xN boards. It doesn't use a shared mutable array, it just uses immutable strings instead. It makes the logic simpler (no clean up since you didn't make a mess!) and the code more readable (where and how the pieces are placed is visible!).

Since we're fixed at 3 rows, the logic is more explicit if we just have 3 mutually recursive functions.

public class Domino3xN {
   static int count = 0;

   public static void main(String[] args) {
      addRow1(8, "", "", "");
      System.out.println(count);
   }

   static void addRow1(int N, String row1, String row2, String row3) {
      if (row1.length() == N && row2.length() == N && row3.length() == N) {
         count++; // found one!
         System.out.format("%s%n%s%n%s%n%n", row1, row2, row3);
         return;
      }
      if (row1.length() > row2.length()) { // not my turn!
         addRow2(N, row1, row2, row3);
         return;
      }
      if (row1.length() < N - 1)
         addRow2(N, row1 + "<>",
                    row2,
                    row3);
      if (row2.length() == row1.length())
         addRow3(N, row1 + "A",
                    row2 + "V",
                    row3);
   }
   static void addRow2(int N, String row1, String row2, String row3) {
      if (row2.length() > row3.length()) { // not my turn!
         addRow3(N, row1, row2, row3);
         return;
      }
      if (row2.length() < N - 1)
         addRow3(N, row1,
                    row2 + "<>",
                    row3);
      if (row3.length() == row2.length())
         addRow1(N, row1,
                    row2 + "A",
                    row3 + "V");
   }
   static void addRow3(int N, String row1, String row2, String row3) {
      if (row3.length() == row2.length()) { // not my turn!
         addRow1(N, row1, row2, row3);
         return;
      }
      if (row3.length() < N - 1)
         addRow1(N, row1,
                    row2,
                    row3 + "<>");
   }
}

You don't often see 3 mutually recursive functions like this, so this should be educational.

提笔书几行 2024-09-05 21:20:09

实现此目的的一种方法是使用 CSP(约束满足问题)方法:

将网格中的每个单元格视为一个变量,具有 4 个可能的值(指示它所占用的多米诺骨牌部分)。有些任务显然是非法的。合法赋值也会将值赋给“相邻变量”。您的目标是为所有 3xN 变量分配合法值。

这里的递归可以帮助您轻松覆盖状态空间。在每次调用时,您尝试通过尝试所有 4 个选项来为下一个未签名的单元格分配一个值。每次成功分配后,您可以递归地调用相同的方法,然后撤消上次分配(这样您就不必克隆任何内容 - 网格数据的一份副本就足够了)。

- 编辑 -
如果你想有效地完成它,以便它在合理的时间内适用于 N 上的大值,你还必须考虑优化,以便放弃一些分配尝试。

One way of doing it is with the CSP (Constraint Satisfaction Problem) approach:

Consider every cell in the grid to be a variable, with 4 possible values (indicating the part of the domino it takes). Some assignments are obviously illegal. Legal assignments assign values to a "neighboring variable" as well. Your goal is to assign all the 3xN variables with legal values.

The recursion here can help you cover the state space easily. On each invocation, you try to assign a value to the next unasigned cell, by trying all the 4 options. After each successfull assignment, you can call the same method recursively, and then undo your last assignment (this way you don't have to clone anything - one copy of the grid data is enough).

--EDIT--
If you want to do it efficiently so that it works for large values on N in reasonable time, you will also have to think about optimizations, in order to discard some assignment attempts.

苄①跕圉湢 2024-09-05 21:20:09

这里有一些提示:

使用固定大小的板,您可以预先计算每个解决方案所采取的确切步骤数,因此终止标准很简单:您只需检查嵌套级别即可。

从一个角开始是一个好主意,因为这意味着您始终可以找到只能以两种不同方式(垂直或水平)覆盖的字段。

这意味着您的分支因子仅为 2,递归深度为 3*N/2,这可能足够小,您可以为每次调用克隆板的状态(通常您会从增量构造新状态)现有状态以节省空间,但这有点难以编程)。

在许多州,不止一个字段只允许两种可能性;通过选择下一个字段的巧妙策略,您可以确保永远不会通过两条不同的路径找到相同的解决方案,因此您甚至不必检查解决方案是否重复。

棋盘的状态必须记录哪些字段是空闲的、哪些字段被占用,而且还要记录哪些字段被同一个多米诺骨牌占用,因此 int 数组可以解决这个问题。

Here are some hints:

With a fixed-size board you can precompute the exact number of steps that each solution takes, so the termination criterion is trivial: you just check the nesting level.

Starting from one corner is a good idea, because it means that you can always find a field that can only be covered in two different ways (vertically or horizontally).

That means that you have a branching factor of only 2, and a recursion depth of 3*N/2, which is probably small enough that you can just clone the sstate of the board for each call (ordinarily you would construct new states incrementally from existing states to save space, but that is a bit harder to program).

In many states here will be more than one field that allows only two possibilities; with a clever strategy for choosing the next field, you can ensure that you will never find the same solution via two different paths, so you don't even have to check the solutions for duplicates.

The state of the board must record which fields are free and which fields are occupied, but also which fields are occupied by the same domino, so an array of int could do the trick.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文