【问题标题】:Tiles Stacking Problem to build a stable stackTiles Stacking Problem 构建稳定的堆栈
【发布时间】:2020-11-23 03:18:14
【问题描述】:

我正在 GeeksForGeeks 上学习动态编程,遇到了 Tiles Stacking Problem 及其解决方法的问题

高度为 n 的稳定塔是由恰好 n 个单位高度的瓷砖组成的塔,垂直堆叠的方式是不会将较大的瓷砖放置在较小的瓷砖上。示例如下:

我们有无限数量的大小为 1、2、...、m 的图块。任务是计算可以用这些瓦片建造的高度为 n 的不同稳定塔的数量,但限制是您可以在塔中最多使用 k 个每种尺寸的瓦片。

注意:当且仅当存在高度 h (1

Input : n = 3, m = 3, k = 1.
Output : 1
Possible sequences: { 1, 2, 3}. 
Hence answer is 1.

Input : n = 3, m = 3, k = 2.
Output : 7
{1, 1, 2}, {1, 1, 3}, {1, 2, 2},
{1, 2, 3}, {1, 3, 3}, {2, 2, 3}, 
{2, 3, 3}.

解决的方法是使用从 1 到 m 的数字来计算长度为 n 的递减序列的数量,其中每个数字最多可以使用 k 次。我们可以使用 n-1 的计数递归地计算 n 的计数。

声明一个二维数组 dp[][],其中每个状态 dp[i][j] 使用从 j 到 m 的数字表示长度为 i 的递减序列的数量。我们需要注意一个数字最多可以使用 k 次这一事实。这可以通过考虑一个数字出现 1 到 k 次来完成。因此我们的递归关系变为:

此外,我们可以使用这样一个事实,即对于固定的 j,我们使用 i 的前 k 个值的连续值。因此,我们可以为每个状态维护一个前缀和数组。现在我们已经摆脱了每个状态的 k 因子。

这个算法我已经读了很多遍了,但我不明白它以及如何证明它的准确性。我试图在互联网上找到该指南,但只有它的变体。请帮我解释一下。

【问题讨论】:

    标签: c++ algorithm dynamic-programming


    【解决方案1】:
    • 请注意,最大尺寸的磁贴 (m) 只能出现在底部。
    • 它的出现是连续
    • 您的重复周期变为:
    T(n,m,k) = SIGMA_{i=0,...,k} T(n-i,m-1,k)
    
    • 然后您必须定义重复的基本情况:
    T(n,m,1) = // can you tell what this is?
    T(n,1,k) = // can you tell what this is?
    T(1,m,k) = m // this is easy
    

    【讨论】:

    • 对不起,我无法理解这里的复现,你如何证明这里的复现?
    • m 大小的图块只能出现在塔的底部。 (连续)出现的次数在0k 之间。之后,我们遇到同样的问题,最大元素m-1 和长度n-i 其中im-tiles 的数量
    • T(1, m, k) 的最后一种情况我认为它不是 1,m。你怎么看?
    • @HoangNam 如果我们只被允许使用一个 tile 并且有 m 个尺寸可供选择(即 T(1, m, k)),我们可以构建 m 个不同的堆栈,每个堆栈只有一个 tile大小不同。
    【解决方案2】:

    我们可以通过形成一个逻辑递归来证明它:

    (A) 如果给定 m 和 k 的最大堆栈高度小于 n,我们无法创建任何堆栈。

    (B) 如果只允许一个图块,我们可以为该图块选择 m 个不同的尺寸。

    (C) 如果只允许一种尺寸,如果k大于等于n,我们可以构造一叠n个尺寸为1的瓦片;否则,零堆栈。

    (D) 对于每个可能堆叠的大小为 m 的图块的计数 x,我们有一种方法乘以堆叠 (n - x) 个图块的方式数,最多使用 (m - 1) 个大小) 因为我们使用了 m。

    为了将递归转换为自下而上的动态规划,我们使用递归的基本情况初始化矩阵,并使用其一般情况逻辑分支填充后续条目。

    这是 JavaScript 中递归的演示(抱歉,我不精通 C++,但第一个函数 f 只计算计数,应该很容易转换):

    // Returns the count
    function f(n, m, k){
      if (n > m * k)
        return 0;
      
      if (n == 1)
        return m;
        
      if (m == 1)
        return n <= k ? 1 : 0;
       
      let result = 0;
    
      for (let x=0; x<=k; x++)
        result += f(n - x, m - 1, k);
        
      return result;
    }
    
    // Returns the sequences
    function g(n, m, k){
      if (n > m * k)
        return [];
      
      if (n == 1)
        return new Array(m).fill(0).map((_, i) => [i + 1]);
        
      if (m == 1)
        return n <= k ? [new Array(n).fill(1)] : [];
       
      let result = [];
    
      for (let x=0; x<=k; x++){
        const pfx = new Array(x).fill(m);
        const prev = g(n - x, m - 1, k);
    
        for (let s of prev)
          result.push(pfx.concat(s));
      }
        
      return result;
    }
    
    var inputs = [
      [3, 3, 1],
      [3, 3, 2],
      [1, 2, 2]
    ];
    
    for (let args of inputs){
      console.log('' + args);
      console.log(f(...args));
      console.log(JSON.stringify(g(...args)));
      console.log('');
    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 2016-05-21
      相关资源
      最近更新 更多