生成子集——幸运的袋子
2016-08-08 13:27 shuaihanhungry 阅读(1203) 评论(0) 编辑 收藏 举报幸运的数字Online Judge
一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3,你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。
现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。
上图即为剪枝后的部分解答树,每个结点即代表一个可能解,只有橙色节点为我们需要的解,例如最左边节点代表1 + 1 + 2 + 3 > 1 * 1 * 2 * 3。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void DFS(vector<int> &X, vector<int> &path, vector<int>::iterator start, int &result) {
int sum = 0, product = 1;
for(vector<int>::iterator iter = path.begin(); iter != path.end(); ++iter) {
sum += *iter;
product *= *iter;
}
if(sum > product) result++;
if(!path.empty() && sum < product) return;
for(vector<int>::iterator iter = start; iter != X.end(); ++iter) {
if(iter != start && *iter == *(iter - 1)) continue;
path.push_back(*iter);
if(path.front() == 1)
DFS(X, path, iter + 1, result);
path.pop_back();
}
}
int main() {
int N;
cin >> N;
vector<int> X(N);
for(int i = 0; i < N; i++) cin >> X[i];
sort(X.begin(), X.end());
int result = 0;
vector<int> path;
DFS(X, path, X.begin(), result);
cout << result << endl;
return 0;
}
上面的解题思想是正确的,但是效率不高,无法通过所有测试用例。下面是牛客上给出的一个解法,可通过所有测试用例。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
std::vector<int> nums;
int n, nxt[1005];
int DFS(int i, int sum, int product) {
if(i >= n) return sum > product;
if(nums[i] > 1 && sum < product) return 0;
return DFS(i + 1, sum + nums[i], product * nums[i]) + DFS(nxt[i], sum, product); //选,不选
}
int solve() {
memset(nxt, 0, sizeof(nxt));
int p = n;
for(int i = n - 1; i >= 0; i--) {
if(i < n - 1 && nums[i + 1] > nums[i]) p = i + 1;
nxt[i] = p;
}
return DFS(0, 0, 1);
}
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
int x; scanf("%d", &x);
nums.push_back(x);
}
sort(nums.begin(), nums.end());
cout << solve() << endl;
}