描述 | |
給定整數集合S和一個目標數T,判斷是否可以從S中挑選一個非空子集,子集中的數相乘的乘積為T。 | |
關於輸入 | |
輸入為兩行。 第一行為目標數T和S中的元素個數N,以空格隔開。 第二行為S中的N個元素,以空格隔開。 其中 N <= 16。 |
|
關於輸出 | |
如果可以,則輸出YES,否則輸出NO。 | |
例子輸入 | |
Sample Input 1:
|
|
例子輸出 | |
Sample Output 1:
|
代碼:
1 //集合里的乘法 2 // 3 //2019-11-11 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 int a[20]; 8 //涉及到除法就要考慮0的特判 9 bool mult(int num, int k, int n){ //試到第k個數.要用乘法湊出num, 一共n個數 10 if(num==a[k]) return true; 11 if(a[k]==0) return false; //一定要注意 12 if(k+1<=n){ 13 if(num%a[k]==0){ 14 if(mult(num/a[k],k+1,n)) //取當前數 15 return true; 16 else 17 return mult(num,k+1,n); //不取當前數 18 } 19 else 20 return mult(num,k+1,n); //不取當前數 21 } 22 return false; 23 } 24 int main(){ 25 int t, n; 26 cin>>t>>n; 27 for(int i = 1; i <= n; i++) 28 cin>>a[i]; 29 if(mult(t,1,n)) 30 cout<<"YES"<<endl; 31 else 32 cout<<"NO"<<endl; 33 return 0; 34 }
備注:
感覺自己這個回溯寫的挺亂的。關鍵在於拆分子問題。用遞歸來暴力枚舉每一個書取或不取。但因為我用的是除法,一定要注意除數不能為0,但如果用直接暴力乘的話就沒有這個問題。
我的代碼寫的太差了,補一個作業范例,思路就超級清晰:
1 #include <iostream> 2 using namespace std; 3 int e[50],found=0,t,card;//數組 e 記錄集合中的元素,found 記錄是否已經找到子集 4 void attempt(int i, int k) 5 { 6 if (found || i>card) return; 7 if (k==t) 8 { 9 cout << "YES"; found=1; return; 10 } 11 attempt(i+1, k);//子集中不包含這個數 12 attempt(i+1, k*e[i]);//子集中包含這個數 13 } 14 int main() 15 { 16 cin >> t >> card; 17 for (int i=1; i<=card; i++) cin >> e[i]; 18 attempt(1,1); 19 if (!found) cout << "NO";//如果沒找到就輸出 NO 20 return 0; 21 }