Codeup_5973:问题 B: 【递归入门】组合的输出

本文介绍了如何使用C语言解决组合输出问题,通过递归和迭代两种方法,详细阐述了解题思路、代码实现以及经验总结。
摘要由CSDN通过智能技术生成

Problem Description

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r < = n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
现要求你不用递归的方法输出所有组合。

Input

一行两个自然数n、r ( 1 < n < 21,1 < = r < = n )。

Output

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,所有的组合也按字典顺序。

Sample Input

5 3

Sample Output

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

原题链接

解题思路

  1. 思路:更新最后一位,最后一位更新到n时,更新上一位。
  2. 声明一个栈,将数字1入栈。
  3. 取栈顶的下一位入栈。
  4. 当栈内元素个数为r时,打印栈内元素,需要出栈一次,更新栈顶。
  5. 当栈顶为n时,需要出栈两次,更新栈顶。
  6. 重复③④⑤操作,栈为空为止。

示例:

  • 栈内元素:1,2,3,此时元素个数等于3,打印,需要一次出栈。
  • 3出栈,3的下一位4入栈,栈内元素:1,2,4。
  • 此时元素个数等于3,打印,需要一次出栈。
  • 4出栈,4的下一位5入栈,栈内元素:1,2,5。
  • 由于栈顶为5,需要两次出栈。
  • 5出栈,2出栈,2的下一位3入栈,栈内元素:1,3。

经验总结

  • 递归思路:
  • 用index记录当前处理的整数的编号,count记录当前组合中数字的个数。
  • 递归边界:
    1. 选择第n + 1个数时结束递归,此时若count == r,则需打印组合。
    2. count == r时结束递归。
  • index从1开始,每个index有两种选择:
    1. 选择当前整数index,count + 1,考虑下一个整数(即index + 1)。
    2. 不选择当前整数index,考虑下一个整数。

代码实现(C)

  1. 迭代方案:
#include <stdio.h>
#include <stdbool.h>

#define MaxSize 21

// 打印组合方案
void print(int a[], int count) {
    for (int i = 0; i < count; ++i) {
        if (i < count - 1)
            printf("%d ", a[i]);
        else
            printf("%d\n", a[i]);
    }
}

int main() {
    int n, r;
    while (~scanf("%d%d", &n, &r)) {
        int top = 0;                    // 栈顶指针top指向栈顶元素后一个位置,初值为0
        int stk[MaxSize];               // 声明栈
        bool needPop = false;           // 记录是否需要出栈
        int index = 1;                  // index记录上一次选择的整数(即栈顶)
        stk[top++] = index;             // 1入栈
        while (top > 0) {               // 一直循环到栈空
            if (top == r) {             // 如果栈内元素个数等于r
                print(stk, top);        // 打印输出栈内元素
                needPop = true;         // 需要出栈最后一位元素
            }
            index = stk[top - 1];       // 取栈顶元素
            if (index == n) {           // 到达整数边界,需要出栈两次
                top--;
                needPop = true;
                continue;
            }
            if (needPop) {              // 出栈
                top--;
                needPop = false;
            }
            if (index < n)              // 未到数字边界
                stk[top++] = index + 1; // 选择栈顶元素的下一个数字入栈
        }
    }
    return 0;
}
  1. 递归方案:
#include <stdio.h>

#define MaxSize 21

int n, r;           // 从n个数中选出r个数

int ans[MaxSize];   // 记录组合方案

// 打印组合方案
void print(int index) {
    for (int i = 0; i < index; ++i) {
        if (i < index - 1)
            printf("%d ", ans[i]);
        else
            printf("%d\n", ans[i]);
    }
}

void dfs(int index, int count) {
    /*递归边界
     * ①选择第n+1个数时,若当前组合中数字个数为r则打印并返回
     * ②当前组合中数字个数为r则打印并返回
     * */
    if (index == n + 1 || count == r) {
        if (count == r)
            print(count);
        return;
    }

    // 选择index
    ans[count] = index;
    dfs(index + 1, count + 1);
    // 不选择index
    dfs(index + 1, count);
}

int main() {
    while (~scanf("%d%d", &n, &r)) {
        // 从1开始选择,初始时组合中的个数为0
        dfs(1, 0);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值