解题思路

  1. 回溯法:使用回溯算法生成所有可能的组合。
  2. 递归:在递归过程中,选择当前数字或不选择,直到达到目标和m。
  3. 字典序:由于我们从小到大选择数字,生成的组合自然是按字典序排列的。

关键点:

  1. 使用回溯法生成组合。
  2. 维护当前和,判断是否达到目标。
  3. 使用列表存储当前组合,达到目标时输出。

算法步骤:

  1. 定义一个回溯函数,接受当前数字、当前和和当前组合。
  2. 在回溯函数中,遍历从当前数字到n的所有数字。
  3. 如果当前和加上当前数字小于等于m,则将当前数字加入组合并递归调用。
  4. 如果当前和等于m,则输出当前组合。
  5. 递归返回后,移除最后一个数字以尝试其他组合。

代码

#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    void backtrack(int n, int m, int start, vector<int>& current_combination, vector<vector<int>>& results) {
        if (m == 0) {
            results.push_back(current_combination);  // 记录当前组合
            return;
        }
        for (int i = start; i <= n; i++) {
            if (i > m) break;  // 如果当前数字大于剩余的m,直接返回
            current_combination.push_back(i);  // 选择当前数字
            backtrack(n, m - i, i + 1, current_combination, results);  // 递归
            current_combination.pop_back();  // 撤销选择
        }
    }
};

int main() {
    int n, m;
    cin >> n >> m;
    Solution solution;
    vector<vector<int>> results;
    vector<int> current_combination;
    
    solution.backtrack(n, m, 1, current_combination, results);
    
    for (const auto& combination : results) {
        for (int num : combination) {
            cout << num << " ";
        }
        cout << endl;  // 输出结果
    }
    
    return 0;
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    static class Solution {
        public void backtrack(int n, int m, int start, List<Integer> currentCombination, List<List<Integer>> results) {
            if (m == 0) {
                results.add(new ArrayList<>(currentCombination));  // 记录当前组合
                return;
            }
            for (int i = start; i <= n; i++) {
                if (i > m) break;  // 如果当前数字大于剩余的m,直接返回
                currentCombination.add(i);  // 选择当前数字
                backtrack(n, m - i, i + 1, currentCombination, results);  // 递归
                currentCombination.remove(currentCombination.size() - 1);  // 撤销选择
            }
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        
        Solution solution = new Solution();
        List<List<Integer>> results = new ArrayList<>();
        List<Integer> currentCombination = new ArrayList<>();
        
        solution.backtrack(n, m, 1, currentCombination, results);
        
        for (List<Integer> combination : results) {
            for (int num : combination) {
                System.out.print(num + " ");
            }
            System.out.println();  // 输出结果
        }
        
        sc.close();
    }
}
def backtrack(n, m, start, current_combination, results):
    if m == 0:
        results.append(current_combination[:])  # 记录当前组合
        return
    for i in range(start, n + 1):
        if i > m:  # 如果当前数字大于剩余的m,直接返回
            break
        current_combination.append(i)  # 选择当前数字
        backtrack(n, m - i, i + 1, current_combination, results)  # 递归
        current_combination.pop()  # 撤销选择

if __name__ == "__main__":
    n, m = map(int, input().split())
    results = []
    backtrack(n, m, 1, [], results)
    
    for combination in results:
        print(" ".join(map(str, combination)))  # 输出结果

算法及复杂度分析

  • 算法:回溯
  • 时间复杂度:,在最坏情况下,可能会生成所有的组合。
  • 空间复杂度:,用于存储当前组合。