給定乙個陣列,裡面有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;
如果不選,那麼k
,s
都不變;
具體過程看以下**,有詳細注釋。
#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 ...