簡體   English   中英

在具有排序約束的數組中生成 k 個數字的組合

[英]Generate combinations of k numbers in an array with ordering constraints

這是我期中考試的問題之一。

請跟蹤以下程序。 修改此程序以編寫一個遞歸程序int combinations(A, n, k) ,您可以打印出存儲在數組An不同數字中的k數字的所有組合,並附加以下規則:

(1) A[0], A[1], ..., A[n-1]的順序必須保持不變並且

(2) 這k數字的序列必須是遞增的。

例如,假設有四個數字4, 1, 2, 3存儲在數組int A[4] 調用這個遞歸函數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 的對應索引中找到數字,並檢查這些數字是否處於遞增順序。

我非常努力地解決這個問題。 但這太難了。

您可以將此視為一個簡單的約束滿足問題,並使用遞歸回溯來解決約束。

正如您所提到的,我們可以天真地生成所有可能的組合,然后追溯選擇我們想要的組合,但是我們已經做了很多分配正確禁止的無用工作。

一種解決方案是在檢測到違反約束時立即中斷遞歸搜索並嘗試不同的可能性。 如果我們達到了滿足序列所有約束的點,我們就會打印結果。 理想情況下,我們會返回一組結果,但不必這樣做可以更輕松地專注於算法。

在滿足約束方面,我們可以通過使用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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM