📜  使用分而治之算法的平铺问题

📅  最后修改于: 2021-09-16 11:18:12             🧑  作者: Mango

给定一个由 n 组成的板,其中 n 的形式为 2 k ,其中 k >= 1(基本上 n 是 2 的幂,最小值为 2)。板上缺少一个单元格(大小为 1 x 1)。使用 L 形瓷砖填充板。 AL 形瓷砖是一个 2 x 2 的正方形,缺少一个大小为 1×1 的单元格。

瓷砖2

图 1:示例输入
这个问题可以用分而治之来解决。下面是递归算法。

// n is size of given square, p is location of missing cell
Tile(int n, Point p)

1) Base case: n = 2, A 2 x 2 square with one cell missing is nothing 
   but a tile and can be filled with a single tile.

2) Place a L shaped tile at the center such that it does not cover
   the n/2 * n/2 subsquare that has a missing square. Now all four 
   subsquares of size n/2 x n/2 have a missing cell (a cell that doesn't
   need to be filled).  See figure 2 below.

3) Solve the problem recursively for following four. Let p1, p2, p3 and
   p4 be positions of the 4 missing cells in 4 squares.
   a) Tile(n/2, p1)
   b) Tile(n/2, p2)
   c) Tile(n/2, p3)
   d) Tile(n/2, p3)

下图显示了上述算法的工作

瓷砖3

图 2:放置第一块瓷砖后

瓷砖4

图 3:重复第一个子方格。

瓷砖5

图 4:显示所有四个子方格中的第一步。例子:

Input :  size = 2 and mark coordinates = (0, 0)
Output : 
-1      1
1       1
Coordinate (0, 0) is marked. So, no tile is there. In the remaining three positions, 
a tile is placed with its number as 1.
Input : size = 4 and mark coordinates = (0, 0)
Output :
-1      3       2       2
3       3       1       2
4       1       1       5
4       4       5       5

以下是上述想法的 C++ 实现:

CPP
// C++ program to place tiles
#include 
using namespace std;
 
int size_of_grid, b, a, cnt = 0;
int arr[128][128];
 
// Placing tile at the given coordinates
void place(int x1, int y1, int x2,
           int y2, int x3, int y3)
{
    cnt++;
    arr[x1][y1] = cnt;
    arr[x2][y2] = cnt;
    arr[x3][y3] = cnt;
}
// Quadrant names
// 1   2
// 3   4
 
// Function based on divide and conquer
int tile(int n, int x, int y)
{
    int r, c;
    if (n == 2) {
        cnt++;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (arr[x + i][y + j] == 0) {
                    arr[x + i][y + j] = cnt;
                }
            }
        }
        return 0;
    }
    // finding hole location
    for (int i = x; i < x + n; i++) {
        for (int j = y; j < y + n; j++) {
            if (arr[i][j] != 0)
                r = i, c = j;
        }
    }
 
    // If missing tile is 1st quadrant
    if (r < x + n / 2 && c < y + n / 2)
        place(x + n / 2, y + (n / 2) - 1, x + n / 2,
              y + n / 2, x + n / 2 - 1, y + n / 2);
 
    // If missing Tile is in 3rd quadrant
    else if (r >= x + n / 2 && c < y + n / 2)
        place(x + (n / 2) - 1, y + (n / 2), x + (n / 2),
              y + n / 2, x + (n / 2) - 1, y + (n / 2) - 1);
 
    // If missing Tile is in 2nd quadrant
    else if (r < x + n / 2 && c >= y + n / 2)
        place(x + n / 2, y + (n / 2) - 1, x + n / 2,
              y + n / 2, x + n / 2 - 1, y + n / 2 - 1);
 
    // If missing Tile is in 4th quadrant
    else if (r >= x + n / 2 && c >= y + n / 2)
        place(x + (n / 2) - 1, y + (n / 2), x + (n / 2),
              y + (n / 2) - 1, x + (n / 2) - 1,
              y + (n / 2) - 1);
 
    // diving it again in 4 quadrants
    tile(n / 2, x, y + n / 2);
    tile(n / 2, x, y);
    tile(n / 2, x + n / 2, y);
    tile(n / 2, x + n / 2, y + n / 2);
 
    return 0;
}
// Driver program to test above function
int main()
{
    // size of box
    size_of_grid = 8;
    memset(arr, 0, sizeof(arr));
    // Coordinates which will be marked
    a = 0, b = 0;
    // Here tile can not be placed
    arr[a][b] = -1;
    tile(size_of_grid, 0, 0);
    // The grid is
    for (int i = 0; i < size_of_grid; i++) {
        for (int j = 0; j < size_of_grid; j++)
            cout << arr[i][j] << " \t";
        cout << "\n";
    }
}


Java
// Java program to place tiles
public class GFG
{
  static int size_of_grid, b, a, cnt = 0;
  static int[][] arr = new int[128][128];
 
  // Placing tile at the given coordinates
  static void place(int x1, int y1, int x2,
                    int y2, int x3, int y3)
  {
    cnt++;
    arr[x1][y1] = cnt;
    arr[x2][y2] = cnt;
    arr[x3][y3] = cnt;
  }
  // Quadrant names
  // 1   2
  // 3   4
 
  // Function based on divide and conquer
  static int tile(int n, int x, int y)
  {
    int r = 0, c = 0;
    if (n == 2)
    {
      cnt++;
      for (int i = 0; i < n; i++)
      {
        for (int j = 0; j < n; j++)
        {
          if (arr[x + i][y + j] == 0)
          {
            arr[x + i][y + j] = cnt;
          }
        }
      }
      return 0;
    }
 
    // finding hole location
    for (int i = x; i < x + n; i++)
    {
      for (int j = y; j < y + n; j++)
      {
        if (arr[i][j] != 0)
        {
          r = i;
          c = j;
        }
 
      }
    }
 
    // If missing tile is 1st quadrant
    if (r < x + n / 2 && c < y + n / 2)
      place(x + n / 2, y + (n / 2) - 1, x + n / 2,
            y + n / 2, x + n / 2 - 1, y + n / 2);
 
    // If missing Tile is in 3rd quadrant
    else if (r >= x + n / 2 && c < y + n / 2)
      place(x + (n / 2) - 1, y + (n / 2), x + (n / 2),
            y + n / 2, x + (n / 2) - 1, y + (n / 2) - 1);
 
    // If missing Tile is in 2nd quadrant
    else if (r < x + n / 2 && c >= y + n / 2)
      place(x + n / 2, y + (n / 2) - 1, x + n / 2,
            y + n / 2, x + n / 2 - 1, y + n / 2 - 1);
 
    // If missing Tile is in 4th quadrant
    else if (r >= x + n / 2 && c >= y + n / 2)
      place(x + (n / 2) - 1, y + (n / 2), x + (n / 2),
            y + (n / 2) - 1, x + (n / 2) - 1,
            y + (n / 2) - 1);
 
    // diving it again in 4 quadrants
    tile(n / 2, x, y + n / 2);
    tile(n / 2, x, y);
    tile(n / 2, x + n / 2, y);
    tile(n / 2, x + n / 2, y + n / 2); 
    return 0;
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    // size of box
    size_of_grid = 8;
 
    // Coordinates which will be marked
    a = 0; b = 0;
 
    // Here tile can not be placed
    arr[a][b] = -1;
    tile(size_of_grid, 0, 0);
 
    // The grid is
    for (int i = 0; i < size_of_grid; i++)
    {
      for (int j = 0; j < size_of_grid; j++)
        System.out.print(arr[i][j] + " ");
      System.out.println();;
    }
  }
}
 
// This code is contributed by divyeshrabadiya07.


C#
// C# program to place tiles
using System;
class GFG
{
     
    static int size_of_grid, b, a, cnt = 0;
    static int[,] arr = new int[128, 128];
      
    // Placing tile at the given coordinates
    static void place(int x1, int y1, int x2,
               int y2, int x3, int y3)
    {
        cnt++;
        arr[x1, y1] = cnt;
        arr[x2, y2] = cnt;
        arr[x3, y3] = cnt;
    }
    // Quadrant names
    // 1   2
    // 3   4
      
    // Function based on divide and conquer
    static int tile(int n, int x, int y)
    {
        int r = 0, c = 0;
        if (n == 2)
        {
            cnt++;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (arr[x + i, y + j] == 0)
                    {
                        arr[x + i, y + j] = cnt;
                    }
                }
            }
            return 0;
        }
       
        // finding hole location
        for (int i = x; i < x + n; i++)
        {
            for (int j = y; j < y + n; j++)
            {
                if (arr[i, j] != 0)
                {
                    r = i;
                    c = j;
                }
                     
            }
        }
      
        // If missing tile is 1st quadrant
        if (r < x + n / 2 && c < y + n / 2)
            place(x + n / 2, y + (n / 2) - 1, x + n / 2,
                  y + n / 2, x + n / 2 - 1, y + n / 2);
      
        // If missing Tile is in 3rd quadrant
        else if (r >= x + n / 2 && c < y + n / 2)
            place(x + (n / 2) - 1, y + (n / 2), x + (n / 2),
                  y + n / 2, x + (n / 2) - 1, y + (n / 2) - 1);
      
        // If missing Tile is in 2nd quadrant
        else if (r < x + n / 2 && c >= y + n / 2)
            place(x + n / 2, y + (n / 2) - 1, x + n / 2,
                  y + n / 2, x + n / 2 - 1, y + n / 2 - 1);
      
        // If missing Tile is in 4th quadrant
        else if (r >= x + n / 2 && c >= y + n / 2)
            place(x + (n / 2) - 1, y + (n / 2), x + (n / 2),
                  y + (n / 2) - 1, x + (n / 2) - 1,
                  y + (n / 2) - 1);
      
        // diving it again in 4 quadrants
        tile(n / 2, x, y + n / 2);
        tile(n / 2, x, y);
        tile(n / 2, x + n / 2, y);
        tile(n / 2, x + n / 2, y + n / 2); 
        return 0;
    }
 
  // Driver code
  static void Main()
  {
     
    // size of box
    size_of_grid = 8;
     
    // Coordinates which will be marked
    a = 0; b = 0;
     
    // Here tile can not be placed
    arr[a, b] = -1;
    tile(size_of_grid, 0, 0);
     
    // The grid is
    for (int i = 0; i < size_of_grid; i++)
    {
        for (int j = 0; j < size_of_grid; j++)
            Console.Write(arr[i,j] + " ");
        Console.WriteLine();
    }
  }
}
 
// This code is contributed by divyesh072019.


Python3
# Python3 program to place tiles
size_of_grid = 0
b = 0
a = 0
cnt = 0
arr = [[0 for i in range(128)] for j in range(128)]
 
def place(x1, y1, x2, y2, x3, y3):
    global cnt
    cnt += 1
    arr[x1][y1] = cnt;
    arr[x2][y2] = cnt;
    arr[x3][y3] = cnt;
     
def tile(n, x, y):
    global cnt
    r = 0
    c = 0
    if (n == 2):
        cnt += 1
        for i in range(n):
            for j in range(n):
                if(arr[x + i][y + j] == 0):
                    arr[x + i][y + j] = cnt
        return 0;   
    for i in range(x, x + n):
        for j in range(y, y + n):
            if (arr[i][j] != 0):
                r = i
                c = j 
    if (r < x + n / 2 and c < y + n / 2):
        place(x + int(n / 2), y + int(n / 2) - 1, x + int(n / 2), y + int(n / 2), x + int(n / 2) - 1, y + int(n / 2))
     
    elif(r >= x + int(n / 2) and c < y + int(n / 2)):
        place(x + int(n / 2) - 1, y + int(n / 2), x + int(n / 2), y + int(n / 2), x + int(n / 2) - 1, y + int(n / 2) - 1)
     
    elif(r < x + int(n / 2) and c >= y + int(n / 2)):
        place(x + int(n / 2), y + int(n / 2) - 1, x + int(n / 2), y + int(n / 2), x + int(n / 2) - 1, y + int(n / 2) - 1)
     
    elif(r >= x + int(n / 2) and c >= y + int(n / 2)):
        place(x + int(n / 2) - 1, y + int(n / 2), x + int(n / 2), y + int(n / 2) - 1, x + int(n / 2) - 1, y + int(n / 2) - 1)
     
    tile(int(n / 2), x, y + int(n / 2));
    tile(int(n / 2), x, y);
    tile(int(n / 2), x + int(n / 2), y);
    tile(int(n / 2), x + int(n / 2), y + int(n / 2));
     
    return 0
 
size_of_grid = 8
a = 0
b = 0
arr[a][b] = -1
tile(size_of_grid, 0, 0)
 
for i in range(size_of_grid):
    for j in range(size_of_grid):
        print(arr[i][j], end=" ")
    print()
 
# This code is contributed by rag2127


输出
-1     9     8     8     4     4     3     3     
9     9     7     8     4     2     2     3     
10     7     7     11     5     5     2     6     
10     10     11     11     1     5     6     6     
14     14     13     1     1     19     18     18     
14     12     13     13     19     19     17     18     
15     12     12     16     20     17     17     21     
15     15     16     16     20     20     21     21     

时间复杂度:
上述递归算法的递归关系可以写成如下。 C 是常数。
T(n) = 4T(n/2) + C
上述递归可以使用 Master Method 求解,时间复杂度为 O(n 2 )

这是如何运作的?
分治算法的工作原理可以用数学归纳法证明。让输入正方形的大小为 2 k x 2 k ,其中 k >=1。
基本情况:我们知道问题可以在 k = 1 时解决。我们有一个 2 x 2 的正方形,缺少一个单元格。
归纳假设:令问题可解为 k-1。
现在我们需要证明如果问题可以解决k-1,那么问题就可以解决k。对于 k,我们在中间放置了一个 L 形瓷砖,我们有四个尺寸为 2 k-1 x 2 k-1 的子方块,如上图 2 所示。所以如果我们能解 4 个子方格,我们就可以解出完整的方格。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程