Given a rectangle of size n x m, find the minimum number of integer-sided squares that tile the rectangle.
    Example 1:
    leetcode 1240. Tiling a Rectangle with the Fewest Squares - 图1
    Input: n = 2, m = 3
    Output: 3
    Explanation: 3 squares are necessary to cover the rectangle.
    2 (squares of 1x1)
    1 (square of 2x2)
    Example 2:
    leetcode 1240. Tiling a Rectangle with the Fewest Squares - 图2
    Input: n = 5, m = 8
    Output: 5
    Example 3:
    leetcode 1240. Tiling a Rectangle with the Fewest Squares - 图3
    Input: n = 11, m = 13
    Output: 6

    解题思路:

    1. class Solution {
    2. public:
    3. map<long, int> set;
    4. int res = 100000001;
    5. int tilingRectangle(int n, int m) {
    6. if (n == m) return 1;
    7. if (n > m) {
    8. int temp = n;
    9. n = m;
    10. m = temp;
    11. }
    12. int *h = new int[n + 1];
    13. memset(h, 0, (n + 1) * sizeof(int));
    14. dfs(n, m, h, 0);
    15. return res;
    16. }
    17. private: void dfs(int n, int m, int h[], int cnt) {
    18. if (cnt >= res) return;
    19. bool isFull = true;
    20. int pos = -1, minH = 100000001;
    21. // 看看数组h是不是满了,没满的话顺便记录一下最低的位置minH和对应的索引pos
    22. for (int i = 1; i <= n; i++) {
    23. if (h[i] < m) isFull = false;
    24. if (h[i] < minH) {
    25. pos = i;
    26. minH = h[i];
    27. }
    28. }
    29. // 如果铺满了
    30. if (isFull) {
    31. res = min(cnt, res);
    32. return;
    33. }
    34. // 没铺满的话,继续铺
    35. /* 这里有一个小trick,把整个数组h的状态映射到一个long的整数类型上。
    36. 这个映射是一对一的映射!!!
    37. 具体方法是把数组看成(m+1)进制的数,就可以转化成一个long类型的整数了。
    38. 因为base的选取是(m+1),而数组中的每个数都不超过m,故肯定是一个一对一的映射!
    39. 即不可能存在两个不一样的数组映射到同一个long类型的整数上。
    40. */
    41. long key = 0, base = m + 1;
    42. for (int i = 1; i <= n; i++) {
    43. key += h[i] * base;
    44. base *= m + 1;
    45. }
    46. if (set.count(key) && set[key] <= cnt) return;
    47. set[key] = cnt;
    48. // 找到和pos一样低的末尾位置
    49. int end = pos;
    50. while (end + 1 <= n && h[end + 1] == h[pos] && (end + 1 - pos + 1 + minH) <= m) end++;
    51. // 找到了pos~end这个最低位置的区间后,从end开始,遍历到pos位置,每次铺一块砖。
    52. // 再继续 dfs
    53. for (int j = end; j >= pos; j--) {
    54. int curH = j - pos + 1;
    55. int next[n + 1];
    56. memcpy(next, h, (n + 1)*sizeof(int));
    57. for (int k = pos; k <= j; k++) {
    58. next[k] += curH;
    59. }
    60. dfs(n, m, next, cnt + 1);
    61. }
    62. }
    63. };