(DFS)幸运袋子

(DFS)幸运袋子

链接:幸运的袋子

题目分析:
一个袋子里面有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<vector>
#include<algorithm>
using namespace std;
int cnt = 0;
void dfs(vector<int> vec, int n, int pos, int sum, int mul)
{
    
    
	for (int i = pos; i<n; i++)
	{
    
    
		sum += vec[i];
		mul *= vec[i];
		//当此时满足sum>mul尝试查找下一个
		if (sum>mul)
		{
    
    
			++cnt;
			dfs(vec, n, i + 1, sum, mul);
		}
		//当此时元素为1时,尝试查找下一个
		else if (vec[i] == 1)
		{
    
    
			dfs(vec, n, i + 1, sum, mul);
		}
		//不满足,跳出此次循环
		else
		{
    
    
			break;
		}
		//搜索下一个位置之前,先恢复sum和mul
		sum -= vec[i];
		mul /= vec[i];
		//去除重复的元素,跳到下一个
		while (i < n - 1 && vec[i] == vec[i + 1])
		{
    
    
			++i;
		}
	}
		
}
int main()
{
    
    
	int n;
	while (cin >> n)
	{
    
    
		vector<int> vec(n, 0);
		for (int i = 0; i < n; i++)
		{
    
    
			cin >> vec[i];
		}
		sort(vec.begin(), vec.end());
		dfs(vec, n, 0, 0, 1);
		cout << cnt << endl;

	}
}

感谢https://blog.csdn.net/Shuffle_Ts/article/details/89415774?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control三毛作者的原博客讲解!

猜你喜欢

转载自blog.csdn.net/cckluv/article/details/110926711