输入样例:
5 3
输出样例:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
解题思路:
组合型递归不同于全排列,全排列中的数字均相同,而组合数中各种组合只能出现一次。
- 全排列:一个数组存储排好序的状态,一个数组用于标志是否访问(去重),还需要一个参数表示当前正枚举到的第几个元素(坑位)。
- 组合数:一个数组存储排好序的状态,一个参数表示当前正枚举到第几个元素,还需要存储序列的前一个元素加一(表示从第几个元素开始组合达到“升序”效果
dfs的剪枝:当已经放好的数字的个数与还能存放的数的个数(相当于还有多少库存)之和,如果小于总坑位(相当于库存不够了,装不满了),则剪枝。
Java代码:
import java.io.*;
public class Main {
static int n;
static int m;
static int []temp;
static StringBuilder ans = new StringBuilder();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] split = br.readLine().split(" ");
n = Integer.parseInt(split[0]);
m = Integer.parseInt(split[1]);
temp = new int[n + 1];
dfs(1, 1);
System.out.print(ans);
}
public static void dfs(int u, int start) {//u表示即将往第u个位置放置
if(u - 1 + n - start + 1 < m)
return;//剪枝 当(u - 1):已经放号的个数 + (n - start + 1)还有的“库存”数
//两者相加 仍然不能填充坑位m,则剪去此枝
if(u > m) {
for(int i = 1; i <= m; i++) {
ans.append(temp[i] + " ");
}
ans.append("\n");
return;
}
for(int i = start; i <= n; i++) {
temp[u] = i;
dfs(u + 1, i + 1);
temp[u] = 0;
}
}
}