把正整数 n 分解为 3 个正整数,如 6=1+2+3,排在后面的数必须大于等于前面的数,输出所有方案。
对于这个问题,如果不知道搜索,应该怎么办呢?当然是三重循环,参考代码如下:
实现
[list2tab]
C++
for (int i = 1; i <= n; ++i) for (int j = i; j <= n; ++j) for (int k = j; k <= n; ++k) if (i + j + k == n) printf("%d = %d + %d + %d\n", n, i, j, k);
Python
for i in range(1, n + 1): for j in range(i, n + 1): for k in range(j, n + 1): if i + j + k == n: print("%d = %d + %d + %d" % (n, i, j, k))
Java
for (int i = 1; i < n + 1; i++) { for (int j = i; j < n + 1; j++) { for (int k = j; k < n + 1; k++) { if (i + j + k == n) System.out.printf("%d = %d + %d + %d%n", n, i, j, k); } }}
考虑上述问题,即将正整数 n 分解成不超过 m 个正整数之和,且排在后面的数必须大于等于前面的数,并输出所有方案。
设一组方案将正整数 n 分解成 k 个正整数 a1,a2,…,ak 的和。将问题分层,第 i 层决定 ai。则为了进行第 i 层决策,我们需要记录三个状态变量:n−∑j=1iaj,表示后面所有正整数的和;ai−1,表示前一层的正整数,以确保正整数递增;以及 i,确保我们最多输出 m 个正整数。为了记录方案,我们用 arr 数组,第 i 项表示 ai. 注意到 arr 实际上是一个长度为 i 的栈。
代码如下:
实现
[list2tab]
C++
int m, arr[103]; // arr 用于记录方案void dfs(int n, int i, int a) { if (n == 0) { for (int j = 1; j <= i - 1; ++j) printf("%d ", arr[j]); printf("\n"); } if (i <= m) { for (int j = a; j <= n; ++j) { arr[i] = j; dfs(n - j, i + 1, j); // 请仔细思考该行含义。 } }}// 主函数scanf("%d%d", &n, &m);dfs(n, 1, 1);
Python
arr = [0] * 103 # arr 用于记录方案def dfs(n, i, a): if n == 0: print(arr[1:i]) if i <= m: for j in range(a, n + 1): arr[i] = j dfs(n - j, i + 1, j) # 请仔细思考该行含义。# 主函数n, m = map(int, input().split())dfs(n, 1, 1)
Java
static int m;// arr 用于记录方案static int[] arr = new int[103];public static void dfs(int n, int i, int a) { if (n == 0) { for (int j = 1; j <= i - 1; j++) System.out.printf("%d ", arr[j]); System.out.println(); } if (i <= m) { for (int j = a; j <= n; ++j) { arr[i] = j; dfs(n - j, i + 1, j); // 请仔细思考该行含义。 } }}// 主函数final int N = new Scanner(System.in).nextInt();m = new Scanner(System.in).nextInt();dfs(N, 1, 1);