C-使用递归功能修改程序

时间:2019-11-23 15:42:22

标签: c recursion

这是我期中考试的问题之一。

请跟踪以下程序。修改该程序以编写一个递归程序int combinations(A, n, k),您可以打印出所有 存储在数组k中的n个不同数字中的A个数字的组合,还有以下附加规则:

(1)必须保留A [0],A [1],...,A [n-1]的顺序,并且

(2)这些k数字的顺序必须按升序排列。

例如,假设数组int A[4]中存储了四个数字4,1,2,3。 调用此递归函数combinations(A, 4, 2)将返回计数3并打印出(1、2),(1、3)和(2,3),或者调用combinations(A, 4, 3)将返回计数1并打印出(1,2,3)。

您的递归程序必须考虑避免不必要的递归函数调用。

老师给出了以下代码作为提示

#include <stdio.h>
#define N 4
int boolfunc(int *var, int m);
int recursivebool(int *var, int n);
int main(){
    int varbool[20];
    recursivebool(varbool, N);
}
int boolfunc(int *var, int m){
    int result=var[0], i;
    for (i=1; i<m; i++) result = (result && var[i]);
    return result;
}

int recursivebool(int *var, int n){
    int localvar[20], i, j;
    if (n == 0){
        for(i=0; i<N; i++) printf("%d ", var[i]);
        printf("%d\n", boolfunc(var, N));
        return;
    }
    for (j=0; j<=1; j++) {
        var[n-1] = j;
        recursivebool(var, n - 1);
    }
}

如果运行此程序,我们将获得如下输出:

0 0 0 0 0
1 0 0 0 0
0 1 0 0 0
1 1 0 0 0
0 0 1 0 0
1 0 1 0 0
0 1 1 0 0 
1 1 1 0 0
0 0 0 1 0
1 0 0 1 0
0 1 0 1 0
1 1 0 1 0
0 0 1 1 0
1 0 1 1 0
0 1 1 1 0
1 1 1 1 1

我可以理解提示程序。我需要使用这个概念来编写int combination(int *A, int n, int k),就像所问的问题一样。据我所知,如果k是2,我可以使用这个概念来找到具有两个1和两个0的场景,如下所示:

1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1

然后,我们可以从相应的索引1中找到数字,并检查数字以查看它们是否按升序排列。

我非常努力地解决了这个问题。但这太困难了。

1 个答案:

答案 0 :(得分:1)

您可以将其作为一个简单的约束满足问题,并使用递归回溯法来解决约束。

正如您提到的,我们可以天真地生成所有可能的组合,然后追溯选择所需的组合,但是随后,我们做了很多无用的工作,这些工作被分配正确地禁止了。

一种解决方案是,一旦检测到违反约束条件就中断递归搜索,并尝试另一种可能性。如果我们达到了满足序列所有约束的地步,我们将打印结果。理想情况下,我们将返回一个结果数组,但不必这样做,这样就可以更轻松地专注于算法。

就满足约束而言,我们可以使用start索引来满足i < j的要求。如果我们向进行中的结果添加数字,则结果数组必须为空,或者数组末尾的现有元素小于我们要添加的元素。除此之外,我们还有k的基本情况。

#include <stdio.h>

void print_arr(int len, int *a);

int combinations_recurse(int *a, int n, int k, int *selected, 
                         int selected_len, int start) {
    if (selected_len == k) {
        print_arr(selected_len, selected);
        return 1;
    }

    int selected_count = 0;

    for (int i = start; i < n; i++) {
        if (!selected_len || selected[selected_len-1] < a[i]) {
            selected[selected_len] = a[i];
            selected_count += combinations_recurse(a, n, k, 
                selected, selected_len + 1, start + 1);
        }
    }

    return selected_count;
}

int combinations(int *a, int n, int k) {
    int selected[n];
    return combinations_recurse(a, n, k, selected, 0, 0);
}

int main() {
    int a[] = {4, 1, 2, 3};
    printf("count: %d\n\n", combinations(a, 4, 2));
    printf("count: %d\n", combinations(a, 4, 3));
    return 0;
}

void print_arr(int len, int *a) {
    printf("[");
    for (int i = 0; i < len - 1; printf("%d, ", a[i++]));
    if (len) printf("%d]\n", a[len-1]); 
    else puts("]");
}

输出:

[1, 2]
[1, 3]
[2, 3]
count: 3

[1, 2, 3]
count: 1