c 實現 遞迴選數問題

2021-10-03 21:33:27 字數 1606 閱讀 3717

給定乙個陣列,裡面有n位正整數,要從這個陣列裡面選取k個數,使得它們的和為s,問有多少種可能的取法;

第一行,乙個整數t(t<=100),指示測試用例的數量。

對於每個情況,有兩行。

第一行,三個整數表示n,k和s.其中k<=n<=16.

第二行n個整數表示n個元素的陣列。

資料保證所有數字都可以以 32 位整數儲存。

對於每種情況,輸出乙個整數,代表可能的取法,獨佔一行。

1103

10123

4567

8910

4

//1+2+7=10

//1+3+6=10

//1+4+5=10

//2+3+5=10

一般思路為三重迴圈暴力破解,但是n³複雜度明顯過高;

首先,我們可以看出在乙個陣列中選擇組合情況,是很明顯的子集列舉問題,我們可以用遞迴處理。

還有,為了降低複雜度,我們可以在選擇的時候做一些合理性剪枝,比如說在小於k個數的時候和已經大於s了,那麼就沒有必要去繼續找了,此趟遞迴就可以結束了;又或者在遞迴的時候已經有了k個數,但是其和還小於s,那麼就可以結束此趟遞迴。

在遍歷到每乙個數a的時候,我們都有兩種選擇,就是這個數選或者不選:

如果選了,那麼s=s-a;k=k-1;

如果不選,那麼ks都不變;

具體過程看以下**,有詳細注釋。

#include

#include

using

namespace std;

int num[17]

;//儲存數列

int count=0;

//滿足條件的組合數

void

selectnumber

(int i,

int&n,

int x,

int&k,

int s)

if(i>=n)

return

;//遍歷終點

if(x>k||s<0)

return

;//剪枝 如果當前個數x大於k 總和<0 的時候

selectnumber

(i+1

,n,x+

1,k,s-num[i]);

//選

//選擇當前i索引點 繼續遍歷下個點i+1 當前節點個數+1 並且s減去這個當前值

//下一次遞迴相當於 求 在剩下的陣列中 求k-(x+1)個數 使得它們的和為s-num[i]

selectnumber

(i+1

,n,x,k,s)

;//不選

//不選當前i索引點 繼續遍歷下個點 x 不變 s不變

}int

main()

selectnumber(0

,n,0

,k,s)

; cout<}return0;

}

這道題是一道非常基礎的遞迴列舉問題,在多加一些合理的剪枝,注意細節,就可以直接過。

P1036 選數 c 遞迴

傳送門 已知 n 個整數 x 1,x 2,x n,以及1個整數k k3 7 12 22 3 7 19 29 7 12 19 38 3 12 19 34 現在,要求你計算出和為素數共有多少種。例如上例,只有一種的和為素數 3 7 19 29。鍵盤輸入,格式為 n,k 1 n 20,kx 1,x 2,x...

week3 作業A題 選數問題 遞迴

這題用遞迴的方法解決,每次都有兩個分支,乙個是選擇這個數,乙個是不選這個數,然後進入下一層,對下乙個數進行判斷,同時在每一步的過程中判斷已選擇的數個數和當前的選擇的數的和,來進行剪枝。先是寫了乙個結構體list,有push back,pop back,size幾個方法 class list void...

P1036 選數 遞迴思想

題目傳送門 題目描述 已知 nnn 個整數 x1,x2,xnx 1,x 2,x nx1 x2 xn 以及111個整數kkk k3 7 12 223 7 12 223 7 12 22 3 7 19 293 7 19 293 7 19 29 7 12 19 387 12 19 387 12 19 38 ...