簡體   English   中英

對於給定的整數a,找到總和為a的所有唯一正整數組合

[英]For a given integer a, find all unique combinations of positive integers that sum up to a

不是作業問題。 我在這里問題,我遇到了這個問題。 有人回答了。 我已經嘗試了很多來理解使用的遞歸,但我無法得到它。 有人可以向我解釋一下嗎?

編寫一個函數,對於給定的數字,通過使用加法和任何等於或小於此數字且大於零的數字,打印出所有不同的方式來生成此數字。

例如,給定a = 5 ,我們有以下七種方法來彌補5:

  • 1,1,1,1,1
  • 1,4
  • 1,1,1,2
  • 1,1,3
  • 2,3
  • 1,2,2

該網站的解決方案是在C ++中:

void printSeq( int num , int a[] , int len , int s )
{
    if( num <= 0 )
    {
        for( int j = 0 ; j < len ; j++ )
            cout << a[ j ] << "," ;
        cout << endl;

        return;
    }

    for(int i = s ; i <= num ; i++)
    {
        a[ len ] = i;
        printSeq( num - i , a , len + 1 , i );
    }
}

int main()
{
    int a[5];
    printSeq(5,a,0,1);
    cin.get();
    return 0;
} 

當遇到這樣的問題時,通常從編輯器/ IDE退一步並通過在白板上繪制一個簡單的案例來思考問題通常是個好主意。 甚至不做偽代碼,只是繪制一個流程圖,說明這個問題的一個簡單案例(例如a = 3 )將如何完全陷入困境。 此外,首先不要擔心重復組合。 嘗試找到一個解決方案,為您提供所有需要的組合,然后改進您的解決方案,不給您重復。 在這種情況下,為什么不看一下a = 3的可管理案例呢? 讓我為你畫一幅畫。 綠色復選標記表示我們已達到有效組合,紅叉表示組合無效。

在此輸入圖像描述

如您所見,我們從三個空子組合開始,然后通過向每個子組合附加一個數字來構建三個新的子組合。 我們想要檢查所有可能的路徑,因此我們選擇1,2和3,最后得到[1][2][3] 如果組合中的數字總和等於3,我們找到了一個有效的組合,所以我們可以停下來檢查這條路徑。 如果組合中的數字總和超過3,則組合無效,我們也可以停止。 如果不是這種情況,我們只是繼續構建組合,直到我們得出有效或無效的解決方案。

因為你的問題似乎主要是關於如何為這類問題制定遞歸解決方案而不是特定語法,你剛剛找到了一個C ++解決方案我將提供一個Python解決方案(它幾乎看起來像偽代碼它就是它所知道的。

def getcombs(a, combo = None):
    # initialize combo on first call of the function
    if combo == None:
        combo = []

    combosum = sum(combo) # sum of numbers in the combo, note that sum([]) == 0
    # simple case: we have a valid combination of numbers, i.e. combosum == a
    if combosum == a:
        yield combo # this simply gives us that combination, no recursion here!
    # recursive case: the combination of numbers does not sum to a (yet)
    else:
        for number in range(1, a + 1): # try each number from 1 to a               
            if combosum + number <= a:  # only proceed if we don't exceed a
                extcombo = combo + [number] # append the number to the combo
                # give me all valid combinations c that can be built from extcombo
                for c in getcombs(a, extcombo):
                    yield c

我們來測試代碼吧!

>>> combos = getcombs(3)
>>> for combo in combos: print(combo)
... 
[1, 1, 1]
[1, 2]
[2, 1]
[3]

這似乎工作正常, a = 5另一個測試:

>>> combos = getcombs(5)
>>> for combo in combos: print(combo)
... 
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3]
[1, 2, 1, 1]
[1, 2, 2]
[1, 3, 1]
[1, 4]
[2, 1, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 3]
[3, 1, 1]
[3, 2]
[4, 1]
[5]

該解決方案包括我們正在尋找的所有七種組合,但代碼仍然會產生重復。 您可能已經注意到,沒有必要使用小於先前所選數字的數字來生成所有組合。 因此,讓我們添加一些代碼,這些代碼只會開始為不小於組合中當前最后一個數字的數字構建extcombo 如果組合為空,我們只需將之前的數字設置為1。

def getcombs(a, combo = None):
    # initialize combo on first call of the function
    if combo == None:
        combo = []

    combosum = sum(combo) # sum of numbers in combo, note that sum([]) == 0
    # simple case: we have a valid combination of numbers, i.e. combosum == a
    if combosum == a:
        yield combo # this simply gives us that combination, no recursion here!
    # recursive case: the combination of numbers does not sum to a (yet)
    else:
        lastnumber = combo[-1] if combo else 1 # last number appended
        for number in range(lastnumber, a + 1): # try each number between lastnumber and a
            if combosum + number <= a:
                extcombo = combo + [number] # append the number to the combo
                # give me all valid combinations that can be built from extcombo
                for c in getcombs(a, extcombo):
                    yield c

再一次,讓我們測試一下代碼吧!

>>> combo = getcombs(5)
>>> for combo in combos: print(combo)
... 
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 4]
[2, 3]
[5]

提出的解決方案可能不是最有效的解決方案,但希望它會鼓勵您遞歸思考。 逐步解決問題,為小輸入繪制一個簡單的案例,一次解決一個問題。

暫時擱置解決方案並查看問題本身:

將此問題與數組(或任何遞歸算法)的插入排序進行比較。 在執行期間的任何時候插入排序我們有一個排序的數組的一部分和另一個未排序的部分。 我們從未分類的部分中選擇一個元素,並在排序的部分中找到它,從而擴展已排序的部分,使問題變小。

在這個問題的情況下,我們可以選擇固定數量的元素,即整數1到問題中的數字(讓我們稱之為N),成為總和為N的序列的一部分。

在任何時候我們都收集了一些總和小於N的數字(比如說X),將問題減少到NX大小,同時也減少了我們在下一次遞歸時從1..N到1 ..(NX)的選擇。

解決方案顯而易見,每個選擇從1到(NX)並遞歸地進行直到X = N. 每次算法達到X = N時,意味着找到排列。

注意:我在解決方案中看到的一個問題是,它需要知道預先找到的排列數。 int a[5]; 如果該值未知,這可能會導致問題。

暫無
暫無

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

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