链接: 幸运的袋子
题目
描述
一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。
输入描述:
第一行输入一个正整数n(n ≤ 1000) 第二行为n个数正整数xi(xi ≤ 1000)
输出描述:
输出可以产生的幸运的袋子数
示例1
输入:
3
1 1 1
输出:
2
思路
- 我们先明确一个式子所表达的含义,题目要求说是要 (a+b>ab),那就说明a,b两个数中一定有一个为1,为什么呢?比如说如果两个值分别是2,3,那么也就不满足题目要求
- 该题要用到递归和回溯的思想,当当前数之和大于当前数之积,那么继续往后进行,在进行递归遍历这些操作之前要先将这个数组进行排序,为什么呢?
排完序后,遍历到不满足条件的位置时,这个位置后面的值都比当前位置大,也就不用再继续往后面进行判断,也就省去了好多步骤,当不满足这个条件时,我们便需要回溯到上一步,比如数组1,1,3,5,7,在3这个位置时,再往后遍历就都不满足条件了,这是就需要回溯到上一步,也就是第二个的1的这个位置,然后第一个1继续与后面的3进行组合判断 - 如果遇到当前位置为1的情况,继续递归下一个位置进行判断
解题步骤
- 如何不符合要求,且当前元素值为1,则继续向后搜索
if(x[i] == 1)
count +=getLuckyPacker(x,n,i+1,sum,mulit);
- 找到符合要求的组合,加1,继续累加后续的值,看是否有符合要求的集合
if(sum > mulit)
count += 1+getLuckyPacker(x,n,i+1,sum,mulit);
- 没有符合条件的组合,那么便回溯
sum -= x[i];
mulit /= x[i];
- 数字相同的球,没有什么区别,都只能算一个组合,所以直接跳过
while(i<n-1 && x[i] == x[i+1])
i++;
完整代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*getLuckyPacket:从当前位置开始搜索符合要求的组合,一直搜索到最后一个位置结束
x[]: 袋子中的所有球
n: 球的总数
pos: 当前搜索的位置
sum: 到目前位置的累加和
multi: 到目前位置的累积值
*/
int getLuckyPacker(vector<int>& x,int n,int pos,int sum,int mulit)
{
int count = 0;
//循环,搜索以位置i开始所有可能的组合
for(int i = pos;i < n;i++)
{
sum += x[i];
mulit *= x[i];
//找到符合要求的组合,加1,继续累加后续的值,看是否有符合要求的集合
if(sum > mulit)
count += 1+getLuckyPacker(x,n,i+1,sum,mulit);
//如何不符合要求,且当前元素值为1,则继续向后搜索
else if(x[i] == 1)
count +=getLuckyPacker(x,n,i+1,sum,mulit);
else
//如何sum大于multi,则后面就没有符合要求的组合了
break;
//要搜索下一个位置之前,首先恢复sum和multit(回溯)
sum -= x[i];
mulit /= x[i];
//数字相同的球,没有什么区别,都只能算一个组合,所以直接跳过
while(i<n-1 && x[i] == x[i+1])
i++;
}
return count;
}
int main() {
int n;
while(cin>>n)
{
vector<int> a(n);
for(int i = 0; i < n;i++)
{
cin>>a[i];
}
sort(a.begin(),a.end());
cout<<getLuckyPacker(a,n,0,0,1)<<endl;;
}
}
// 64 位输出请用 printf("%lld")