幸运袋子(详解)
題目分析
??一個袋子里面有n個球,每個球上面都有一個號碼(擁有相同號碼的球是無區別的)。如果一個袋子是幸運的當且僅當所有球的號碼的和大于所有球的號碼的積。
例如:如果袋子里面的球的號碼是{1, 1, 2, 3},這個袋子就是幸運的,因為1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
??你可以適當從袋子里移除一些球(可以移除0個,但是別移除完),要使移除后的袋子是幸運的。現在讓你編程計算一下你可以獲得的多少種不同的幸運的袋子。
解題思路
??這道題的本質是在集合中找出符合條件的子集。
??對于兩個任意正整數a,b來說,如果a+b<ab,則必須有一個數為1,可以用數論來證明,這里不再贅述。
??推廣到任意k個正整數,假設a1,a2,…ak,如果不滿足條件,即sum<=multi,如果再選一個數使sum+b > multib,這個b一定是1,相反,如果選擇的b>1,則sum+b < multi*b,那么a1,a2,…ak,b就不滿足給定的條件。
??所以要將這些球進行升序排序。每次從小到大選擇,當選擇到a1,a2,…ak-1時滿足給定條件,再增加ak是不滿足條件,那么ak必然要大于等于之前的最大值,如果繼續向后選擇更大的數,必然無法滿足給定條件。
??如果有多個1,并且k=1使不滿足條件,但是下一個元素仍為1,就可以滿足條件,所以當位置吐過是1,雖然不滿足條件,但是應該繼續向后搜索,因為仍然有可能滿足條件。
對于重復的數字,組合只能算一個,所以要跳過這個數字,也就是去重
代碼實現(必要的地方有注釋)
#include <iostream> #include <algorithm> #include <vector>using namespace std;int getLuckBox(vector<int> x, size_t n, size_t pos, int sum, int multi) {int count = 0;for (size_t i = pos; i < n; ++i){sum += x[i];multi *= x[i];if (sum > multi){//如果當前位置可以滿足要求,就繼續從下一個位置開始count += 1 + getLuckBox(x, n, i + 1, sum, multi);}else if (x[i] == 1){//如果這個位置是1并且不滿足,可以從下一個位置嘗試count += getLuckBox(x, n, i + 1, sum, multi);}else{//如果當前位置不滿足,那么之后更大的數字也不可能滿足,直接直接返回,不再查找break;}//在搜索下一個位置前,要先恢復sum和multisum -= x[i];multi /= x[i];//如果喝下一個位置一樣,就直接跳過,不能有重復while (i < n - 1 && x[i] == x[i + 1]){++i;}}return count; }int main() {size_t n;while (cin >> n){vector<int> x;for (size_t i = 0; i < n; ++i){int tmp;cin >> tmp;x.push_back(tmp);}//按升序排序sort(x.begin(), x.end());cout << getLuckBox(x, n, 0, 0, 1);}return 0; }總結
- 上一篇: C/C++求一个整数的二进制中1的个数(
- 下一篇: SpringBoot 自带工具类~Obj