网易2017内推笔试编程题合集(二)-幸运袋子

本文通过一个具体实例介绍了如何使用树的深度优先搜索(DFS)和剪枝技巧来解决问题,并提供了两种不同实现方式的代码示例。文章首先解释了基本思路,随后给出了第一版代码,接着对代码进行了优化,最后总结了DFS与剪枝思想的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:


这个题的基本思路是利用树的深度遍历(dfs)和剪枝操作,下面我们来看看第一版代码:

<pre name="code" class="cpp">#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<fstream>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;

class solution{
public:
	void get_number(vector<int>&tab,int sum,int pro,int begin){
		int size = tab.size();
		for (int i = begin; i < size; i++){
			if (i>0 ? sum + tab[i]>pro*tab[i]:sum + tab[i]>=pro*tab[i]){//剪枝操作
				stk.push_back(tab[i]);
				if (stk.size() >= 2){
					re++;
					//total.push_back(stk);
				}
				get_number(tab,sum+tab[i],pro*tab[i],i+1);
				stk.pop_back();
			}
			while(i+1<size&&tab[i] == tab[i + 1])i++;//先将它们排序,如果有两个相同的数就直接跳过
			//因为前一个数已经包含了和它相等的后续数的所有情况
		}
	}
	int re;
	vector<int>stk;
	//vector<vector<int>>total;
};

int main(){
	//ifstream fin("C:\\Users\\Dell\\Desktop\\data.txt");
	vector<int>tab;
	int num,tmp;
	solution aa;
	while (cin >>num){
		for (int i = 0; i < num; i++){
			cin >> tmp;
			tab.push_back(tmp);
		}
		aa.re = 0;
		int sum = 0, pro = 1;
		sort(tab.begin(),tab.end());
		aa.get_number(tab,sum,pro,0);
		cout << aa.re << endl;
		//for (int i = 0; i < aa.total.size();i++){
		//	for (int j = 0; j < aa.total[i].size(); j++)cout << aa.total[i][j] <<" ";
		//	cout << endl;
		//}
		tab.clear();
		//aa.total.clear();
	}
	return 0;
}

测试结果:

算法中树的逻辑遍历关系是:


优化:

因为在第一版的代码中,我有将数出栈和入栈,但是这种操作是非必须的,因为我们可以再利用另外一个变量来保存目前栈中元素的个数,也就是说在访问到上图的每一个节点的时候,会有一个四元组来表示当前的情况,它们分别是当前的和sum,当前的乘积pro,当前栈中元素的个数num,当前结点在数组中的下标begin。所以有了这个四元组我们就无需出栈和入栈操作。下面是优化的代码:

#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<fstream>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;

class solution{
public:
	void get_number(vector<int>&tab, int sum, int pro, int begin, int num){
		int size = tab.size(), temp = num;
		for (int i = begin; i < size; i++){
			if (i>0 ? sum + tab[i]>pro*tab[i]:sum + tab[i] >= pro*tab[i]){
				temp++;
				if (temp >= 2)re++;
				get_number(tab, sum + tab[i], pro*tab[i], i + 1, temp);
			}
			while (i + 1<size&&tab[i] == tab[i + 1])i++;
		}
	}
	int re;
};

int main(){
	//ifstream fin("C:\\Users\\Dell\\Desktop\\data.txt");
	vector<int>tab;
	int num, tmp;
	solution aa;
	while (cin >> num){
		for (int i = 0; i < num; i++){
			cin >> tmp;
			tab.push_back(tmp);
		}
		aa.re = 0;
		int sum = 0, pro = 1;
		sort(tab.begin(), tab.end());
		aa.get_number(tab, sum, pro, 0, 0);
		cout << aa.re << endl;
		tab.clear();
	}
	return 0;
}
测试结果:

总结:

利用数的深度遍历和剪枝思想的题目目前可以分为两大类:

第一类:元素之间的操作顺序是没有要求的,我们可以将它排序,然后从小到大处理,这种情况就像本题所示,这种情况一般要考虑元素的重复出现的情况;

第二类:元素之间的操作顺序是有要求的,也就是操作的先后顺序和测试用例的出现的顺序一样,这种情况可以看我的另外一篇博客小萌的包裹:

http://blog.youkuaiyun.com/caoyan_12727/article/details/52059908,这种情况要求处理的顺序就是按元素出现的顺序从左到右。这种情况一般无需考虑元素的重复。这样对每一个元

素只有选择和不选择两种情况!!!!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值