题目:
这个题的基本思路是利用树的深度遍历(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,这种情况要求处理的顺序就是按元素出现的顺序从左到右。这种情况一般无需考虑元素的重复。这样对每一个元
素只有选择和不选择两种情况!!!!