import java.util.*; public class Main { /** * 解题思路: (深度优先算法dfs) * 还是那句总结的话: * 寻找最优多用动态规划 * 输出所有情况多用dfs * 因为本题是需要按字典序排序输出,因此我们在dfs之前对于要穷举的元素按字典序进行排序即可, * 只不过本题是数字,因此我们不需要进行排序,因为按从 1 递增的顺序就是按字典序的顺序穷举 * @param args */ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int m = scanner.nextInt(); Deque<Integer> temp = new LinkedList<>(); dfs(n,m,temp,0,0); } } /** * 总体思路较为简单,但是本解法中有以下两个较为巧妙的点 * 1: 因为题目中是需要按照字典序进行输出,且数字不可以重复用,因此我们这里就在 dfs 的参数上面增加了 * foreNum 参数,来记录前一个数字的值,方便我们满足以上两个条件,但是这个就要求我们调用的时候这个 * 参数传入 0 ,就是从 1 开始到 maxNum 的数字可用 * 2: 本 dfs 我们可以发现没有判断 curSum > target 的情况,因为我们在循环的过程中加了如下判断 * (target-curSum) == i || (target-curSum) > 2*i * 因为数字是递增的且不会重复,因此要想满足继续递归下去还有可以满足的数字集合,因此只有以下两种情况 * 1) curSum + 要添加的数字 == target * 2) (target-curSum) > 2*i * 这个条件的解释为 因为 curSum + 要添加的数字 != target,所以我们至少要添加两个数字,又因为数 * 字是递增的且不会重复,因此这两个数字的和最少为 2*要添加的数字+1 ,因此若 * target-curSum < 2*要添加的数字+1 则绝对不可能出现两个数字满足该组数字相加为 target,因此 * 不需要进行dfs下去了,少了很多次无用的遍历 * 由以上这两个条件的筛选之后,就不可能出现 curSum > target 的情况了 * @param maxNum 可用数字的最大值 * @param target 目标值 * @param temp 临时记录前面所选数字 * @param foreNum 前一个选中的数字 * @param curSum 已选中的数字的和 */ private static void dfs (int maxNum, int target, Deque<Integer> temp, int foreNum, int curSum) { if (curSum == target) { for (int n : temp) { System.out.print(n + " "); } System.out.println(); } for (int i = foreNum+1; i <= maxNum; i++) { if ((target-curSum) == i || (target-curSum) > 2*i) { temp.addLast(i); dfs(maxNum,target,temp,i,curSum+i); //回溯 temp.pollLast(); } } } }