📜  门| GATE CS 2019 |第 44 题(1)

📅  最后修改于: 2023-12-03 15:28:38.215000             🧑  作者: Mango

题目描述

给定一个非负整数 $n$,请找到能够表示 $n$ 的所有组合,每个组合都是由数字 $1, 3, 4$ 构成的。输出时,每个组合升序输出。

输入格式

一个非负整数 $n$。

输出格式

按照升序输出能够表示 $n$ 的所有组合,每个组合占一行。

样例
输入:
5

输出:
1 1 1 1 1
1 1 3
1 4
3 3
解题思路

由于组合中只有数字 1、3、4,我们可以把问题转化为元素为 1、3、4 的组合求和,使得和恰好为 n。

考虑使用动态规划的思想解决该问题。

设 dp[i] 为元素为 1、3、4 的组合求和为 i 时,可能的组合方式。

对于一个数字 i,它只能由 i - 1、i - 3、i - 4 这三个数字转移而来。因此,可以把 dp 数组的初始值设为 dp[0] = 1,其他初始值为 0,然后从 1 开始递推计算 dp 数组。

具体来讲,对于求解 dp[i],有如下转移方程:

$$dp[i] = \sum_{j \in {1,3,4}} dp[i-j]$$

(其中 $\sum$ 表示求和运算)

最终,dp[n] 即为所求,表示元素为 1、3、4 的组合求和为 n 时,所有可能的组合方式。

算法实现

以下为该问题的 Python 代码实现:

def combination_sum(n):
    dp = [0] * (n + 1)
    dp[0] = 1

    for i in range(1, n + 1):
        for j in [1, 3, 4]:
            if i >= j:
                dp[i] += dp[i-j]

    combinations = []
    for i in range(1, n + 1):
        if dp[i] > 0:
            combination = []
            j = i
            while j > 0:
                if j >= 4 and dp[j-4] > 0:
                    combination.append(4)
                    j -= 4
                elif j >= 3 and dp[j-3] > 0:
                    combination.append(3)
                    j -= 3
                elif j >= 1 and dp[j-1] > 0:
                    combination.append(1)
                    j -= 1
            combinations.append(combination)

    combinations.sort()
    for combination in combinations:
        print(" ".join(str(x) for x in combination))

其中,dp 数组的长度为 $n+1$,因为需要计算 $dp$ 的值。在计算 dp 数组中每个元素时,需要遍历 1、3、4 这三个数字,对于 j 在这个范围内的情况,如果 i > j,做如下操作:

$$dp[i] += dp[i-j]$$

即把 dp[i-j] 的值加到 dp[i] 上面。

当 dp 数组计算完成后,我们需要找到所有可能的组合方式,可以依照 dp 数组中每个元素 j 的值,倒推出所有可能的组合方式(由数字 1、3、4 组成)。具体来讲,我们可以从dp[n]开始往前推,找到所有满足条件的组合,例如,求 dp[n] 时,如果 dp[n] 的值不为 0 就可以找到一种组合方式,然后往前推到 dp[n-1],继续找到所有满足条件的组合,直到推到 dp[0] 即可。

最后,按升序输出所有组合就可以了。

总结

该问题是一道动态规划问题,主要考察对动态规划思想的理解和运用。我们可以使用动态规划的方法计算出所有可能的组合方式,然后再按升序输出即可。