回溯算法求组合数中,backtracking函数一般为:
void backtracking(int pre,int n,int k){
if(singlePath.size()==k){
result.push_back(singlePath);
return;
}
for(int i=pre+1;i<=n;i++){
singlePath.push_back(i);
backtracking(i,n,k);
singlePath.pop_back();
}
}
然而,这个backtracking函数仍旧有值得优化的地方!
例如求组合数,回溯流程如下图,其中被红叉标记的地方都是没有意义、浪费掉的操作!——明明是这一层就可以排除掉的操作,结果到下一层,不但没有终止递归并输出结果,还发现pre+1已经大于n,结果还得回溯,确实是浪费、没有意义!
究其原因,就是因为执行完这些操作时,会发现剩下的元素不能够满足还需要的元素,导致最终无法输出组合数!
这些操作可以通过for循环的条件来避免!
未加入当前元素时,已装入元素个数为singlePath.size(),
设当前加入元素为i,则剩余元素为i+1, ..., n-1, n,总共n-i个元素。
加入当前元素后,还需要多少元素才能组成组合数呢?还需要k-singlePath.size()-1个(注意,这里的判断还在for循环的条件里面,还没执行到singlePath的push_back()函数!!!)
所以,循环条件应当为,即。
优化后代码:
void backtracking(int pre,int n,int k){
if(singlePath.size()==k){
result.push_back(singlePath);
return;
}
for(int i=pre+1;i<=n-(k-singlePath.size())+1;i++){
singlePath.push_back(i);
backtracking(i,n,k);
singlePath.pop_back();
}
}