選數問題
給定n個數字,從中選擇k個使他們的和爲s,求有幾種組合方式。
第一行會給一個T(T<=100),表示測試數據的組數,每一組中有兩行,第一行中有三個數字n,k,s;第二行給定n個數字。
將可能的組合方式數輸出。保證k<=n<=16,所有的數字範圍都在32位整數的表示範圍內。
sample input:
1
10 3 10
1 2 3 4 5 6 7 8 9 10
sample output:
4
思路:
- 由於題目給定了數字範圍不會太大,所以當然可以無腦暴力,寫個循環,每次保證第i個數被取到,再嵌套循環取i+1位置的數字,循環檢查是否能k個數字加起來等於s,若等於就count++;最後輸出count就可以。
- 可以使用遞歸的方式來解決,其實原理比較像深搜(一條樹的分支走到黑然後返回),需要判斷的就是他的結束條件,只有當k==0(可以用的數字用完了)並且sum == 0(恰好等於想得到的值)才說明這個選擇是對的,返回值1。
- 對於每一層遞歸,相當於是一個二叉樹,有兩個選擇方向:選擇當前數或者不選擇;對他們的結果求和就能返回答案。
- 對於判斷條件(begin>=length)一定要注意他放置的位置,需要在判斷完+1之後再判斷是否大於等於,如果需要選擇的數字在最後一位的話,將該判斷條件放到前面會導致
組合方式缺少。或者可以寫兩個判斷條件,先判斷if(begin>length),在完成成功判斷後,再判斷一遍if(begin>=length) - 由於這裏我們需要計算數組的長度,所以最好使用動態數組,如果自己創建數組的話需要注意,將數組傳入函數後,使用sizeof(a)來做是錯誤的,他會返回數組的大小*8,返回地址長度,所以比較建議使用vector,並用size()取數組長度。
#include <iostream>
#include <string>
#include <algorithm>
#include<cstdio>
#include<vector>
using namespace std;
ind(vector<int> a,int begin,int k,int sum)
{
int length=a.size();
if(k==0&&sum!=0) return 0;//sum不對
if(k==0&&sum==0) return 1;
if(begin>=length) return 0;//這裏一定一定一定要在這裏,不能放在前面判斷;如果輸出的是最後一個數,需要在n+1位置上返回
return find(a,begin+1,k-1,sum-a[begin])+find(a,begin+1,k,sum);//向下檢索,選擇當前數或者不選擇
}
int main()
{
int t=0;
cin>>t;
while(t--)
{
vector<int> arr;
int n=0,k=0,s=0;
cin>>n>>k>>s;
for(int i=0;i<n;i++)
{
int temp=0;
cin>>temp;
arr.push_back(temp);
}
int ans=find(arr,0,k,s);
cout<<ans<<endl;
}
return 0;
}