如何计算填充一个2 x N的地板所需的1×1、1×2和2×1瓷砖的可能组合数量?

huangapple go评论74阅读模式
英文:

How to count how many possible combination of 1x1, 1x2, 2x1 tiles to fill a 2 x N floor?

问题

我刚刚做了一个技术测试,对于这个任务感到困惑。我的目标是理解如何解决这个“覆盖地板”问题。老实说,我不知道从哪里开始。

任务如下:

  1. 有一个2 x N的地板。
  2. 我们有1x1、1x2和2x1的瓷砖来填充地板。

问题如下:

  1. Solution(1)的预期输出是2,实际输出也是2。
  2. 然而,Solution(2)的预期输出是7,实际输出却是3。

当前的解决方案是:

  1. 1x1的瓷砖总是可以填满2 x N的地板,所以可能的方法从1开始。
  2. 如果剩余的地板面积对2取模等于0,则可能的方法增加1。

当前解决方案的问题在于它没有区分1x2和2x1的瓷砖。所以对于Solution(2),实际输出是3而不是7。

代码如下:

package main

import "fmt"

// Solution is your solution code.
func Solution(n int) int {
	possibleWays := 1

	floorArea := 2 * n
	// Your code starts here.

	for i := floorArea - 1; i >= 0; i-- {
		residualFloorArea := floorArea - i
		fmt.Println(i, residualFloorArea)
		if residualFloorArea%2 == 0 {
			fmt.Println("punch")
			possibleWays += 1
		}
	}

	return possibleWays
}

func main() {
	fmt.Println(Solution(1))
	fmt.Println("next")
	fmt.Println(Solution(2))
}

以上是要翻译的内容。

英文:

I just did a technical test and was confused with this task. My goal is to understand how to solve this 'Cover the floor' problem. Honestly, I have no idea where to start with.

The task is:

  1. There is a floor 2 x N floor.
  2. We have 1x1, 1x2, 2x1 tiles to fill the floor.

The problem is:

  1. Solution(1) expected output is 2 and actual output is 2.
  2. However, Solution(2) expected output is 7 and actual output is 3.

The current solution is to:

  1. 1x1 always can fill 2 x N floor, so the possibleWays starts from 1.
  2. If residual floor mod 2 is 0 then possibleWays increased by 1.

The problem of the current solution is that it do not differentiate between 1x2 and 2x1 tiles. So for Solution(2) the actual output is 3 instead of 7.

The code

package main

import "fmt"

// Solution is your solution code.
func Solution(n int) int {
	possibleWays := 1

	floorArea := 2 * n
	// Your code starts here.

	for i := floorArea - 1; i >= 0; i-- {
		residualFloorArea := floorArea - i
		fmt.Println(i, residualFloorArea)
		if residualFloorArea%2 == 0 {
			fmt.Println("punch")
			possibleWays += 1
		}
	}

	return possibleWays
}

func main() {
	fmt.Println(Solution(1))
	fmt.Println("next")
	fmt.Println(Solution(2))
}

答案1

得分: 1

这主要是一个简单的组合谜题,而不是一个编程练习。关键是计算填充2xN网格的方法数,以及填充带有前两个方块之一的2xN网格的方法数。这给出了递推关系,可以进行计算。

设F(N)为填充2xN网格的方法数,G(N)为填充带有前两个方块之一的网格的方法数。

我们可以从左边开始枚举填充网格的方式(注意不要重复计数):

A...
A...

A...
BB..

AA..
B...

A...
B...

AA..
BB..

因此,F(N) = 2F(N-1) + 2G(N-1) + F(N-2)

对于G也是一样(这里#表示已经填充的方块):

#...
A...

#...
AA..

因此,G(N) = F(N-1) + G(N-1)

我们还有基本情况:F(0) = 1,G(0) = 0,F(1) = 2,G(1) = 1。

根据这些递推关系,我们可以通过O(N)次算术运算迭代地解决这个问题:

package main

import "fmt"

func F(N int) int {
	f0, f1 := 1, 2
	g1 := 1
	for i := 0; i < N; i++ {
		f1, g1, f0 = 2*f1+2*g1+f0, f1+g1, f1
	}
	return f0
}

func main() {
	for i := 0; i < 10; i++ {
		fmt.Println(i, F(i))
	}
}
英文:

This is mainly a simple combinatorial puzzle, rather than a programming exercise. The trick is to count the number of ways of tiling a 2xN grid, but also a 2xN grid with one of the first two squares already filled. This gives you recurrence relations, which can be solved for compuationally.

Let F(N) be the number of ways of tiling a 2xN grid, and G(N) the number of ways of tiling the grid with one of the first two squares already filled.

We can enumerate ways of starting filling the grids from the left (being careful not to count anything twice):

A...
A...

A...
BB..

AA..
B...

A...
B...

AA..
BB..

Thus, F(N) = 2F(N-1) + 2G(N-1) + F(N-2)

Same for G (here # is the piece that's already filled):

#...
A...

#...
AA..

So G(N) = F(N-1) + G(N-1)

We also have the base cases: F(0) = 1, G(0)=0, F(1) = 2, G(1) = 1.

From these recurrence relations, we can solve the problem iteratively in O(N) arithmetic operations:

package main

import &quot;fmt&quot;

func F(N int) int {
	f0, f1 := 1, 2
	g1 := 1
	for i := 0; i &lt; N; i++ {
		f1, g1, f0 = 2*f1+2*g1+f0, f1+g1, f1
	}
	return f0
}

func main() {
	for i := 0; i &lt; 10; i++ {
		fmt.Println(i, F(i))
	}
}

答案2

得分: 1

一个更详细和详尽的尝试:

假设覆盖一个2xN网格的方法数为x_n,覆盖一个2xN+1网格的方法数为y_n,覆盖一个2xN+2网格的方法数为z_n。

基本情况:

  • x_0 = 1,y_0 = 1,z_0 = 2
  • x_1 = 2,y_1 = 3,z_1 = 5

归纳步骤,N >= 2:

       -- --
      |  |  |
 -- -- -- --  ...
|xx|  |  |  |
 -- -- -- --

考虑2xN + 2网格的最左边的单元格,如果它被一个1x1的瓷砖覆盖,剩下的部分就是一个2xN + 1网格,否则,它被一个1x2的瓷砖覆盖,剩下的部分就是一个2xN网格。因此,

z_n = x_n + y_n

    -- --
   |  |  |
 -- -- --  ...
|xx|  |  |
 -- -- --

考虑2xN + 1网格的最左边的单元格,如果它被一个1x1的瓷砖覆盖,剩下的部分就是一个2xN网格,否则,它被一个1x2的瓷砖覆盖,剩下的部分就是一个2x(N-1) + 1网格。因此,

y_n = x_n + y_(n-1)

 -- --
|xx|  |
 -- --  ...
|  |  |
 -- --

考虑2xN网格的左上角,如果它被一个1x1的瓷砖覆盖,剩下的部分就是一个2x(N-1) + 1网格,如果它被一个1x2的瓷砖覆盖,剩下的部分就是一个2x(N-2) + 2网格,否则,它被一个2x1的瓷砖覆盖,剩下的部分就是一个2x(N-1)网格。因此:

x_n = y_(n-1) + z_(n-2) + x_(n-1)

用x_n + y_n替换z_n,我们有:

  • x_n = x_(n-1) + x_(n-2) + y_(n-1) + y_(n-2)
  • y_n = x_n + y_(n-1)

现在,只需迭代计算每个值:

package main

import "fmt"

// Solution is your solution code.
func Solution(n int) int {
    if n == 0 {
        return 1
    } else if n == 1 {
        return 2
    }

    x := make([]int, n + 1)
    y := make([]int, n + 1)
    x[0] = 1
    y[0] = 1
    x[1] = 2
    y[1] = 3

    for i := 2; i <= n; i++ {
        x[i] = x[i - 1] + x[i - 2] + y[i - 1] + y[i - 2]
        y[i] = x[i] + y[i - 1]
    }

    return x[n]
}

func main() {
    fmt.Println(Solution(1))
    fmt.Println("next")
    fmt.Println(Solution(2))
}

你可以不使用切片,但这样更容易理解。Playground演示

英文:

A more descriptive and trivially exhaustive attempt:

Call the number of ways to cover a 2xN grid is x_n, the number of ways to cover a 2xN+1 grid is y_n, and the number of ways to cover a 2xN + 2 grid is z_n.

Base cases:

  • x_0 = 1, y_0 = 1, z_0 = 2
  • x_1 = 2, y_1 = 3, z_1 = 5

Induction step, N >= 2:

       -- --
      |  |  |
 -- -- -- --  ...
|xx|  |  |  |
 -- -- -- --

Consider the leftmost cell of the 2xN + 2 grid, if it is covered by a 1x1 tile, then the remaining is a 2xN + 1 grid, otherwise, it is covered by a 1x2 tile, the remaining would be a 2xN grid. Hence,

z_n = x_n + y_n

    -- --
   |  |  |
 -- -- --  ...
|xx|  |  |
 -- -- --

Consider the leftmost cell of the 2xN + 1 grid, if it is covered by a 1x1 tile, the remaining would be a 2xN grid, otherwise, it is covered by a 1x2 tile, the remaining would be a 2x(N-1) + 1 grid. Hence,

y_n = x_n + y_(n-1)

 -- --
|xx|  |
 -- --  ...
|  |  |
 -- --

Consider the topleft corner of the 2xN grid, if it is covered by a 1x1 tile, the remaining would be a 2x(N-1) + 1 grid, if it is covered by a 1x2 tile, the remaining would be a 2x(N-2) + 2 grid, otherwise, it is covered by a 2x1 tile, the remaining would be a 2x(N-1) grid. Hence:

x_n = y_(n-1) + z_(n-2) + x_(n-1)

Replace z_n with x_n + y_n, we have:

  • x_n = x_(n-1) + x_(n-2) + y_(n-1) + y_(n-2)
  • y_n = x_n + y_(n-1)

Now, just iteratively calculate each value:

package main

import &quot;fmt&quot;

// Solution is your solution code.
func Solution(n int) int {
    if n == 0 {
        return 1
    } else if n == 1 {
        return 2
    }

    x := make([]int, n + 1)
    y := make([]int, n + 1)
    x[0] = 1
    y[0] = 1
    x[1] = 2
    y[1] = 3

    for i := 2; i &lt;= n; i++ {
        x[i] = x[i - 1] + x[i - 2] + y[i - 1] + y[i - 2]
        y[i] = x[i] + y[i - 1]
    }

    return x[n]
}

func main() {
    fmt.Println(Solution(1))
    fmt.Println(&quot;next&quot;)
    fmt.Println(Solution(2))
}

You can do it without a slice but this is easier to understand. Playground demonstration

huangapple
  • 本文由 发表于 2022年12月26日 16:14:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/74918422.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定