dfs 回溯框架和应用的简单分析

首先明确回溯框架的使用范围

  • 求解方案(分为两种)

    1.求解方案的种数(楼梯,硬币找零)

    2.求解具体的方案 (硬币找零的方案,八皇后,全排列,子集,组合,数独等)

  • 求最优解(一般可以用dp优化)

    如果非要回溯的话,要用备忘录来优化!

框架介绍

1.方案数类

//一般都是这样再添加一些东西
void dfs(int n){
	//递归结束条件
	if(...) {
		res++;
		return;
	}
	for(int i=0;i<n;i++){
		//跳过不符合要求的
		if(...) continue;
		//做选择
		dfs(...);
	}

举个简单例子吧!

上楼梯的问题其实就是回溯问题(可以自己画出递归树,方便理解)

/*3089:爬楼梯

    查看
    提交
    统计
    提问

总时间限制:
    1000ms
内存限制:
    65536kB

描述

    树老师爬楼梯,他可以每次走1级或者2级,输入楼梯的级数,求不同的走法数
    例如:楼梯一共有3级,他可以每次都走一级,或者第一次走一级,第二次走两级
    也可以第一次走两级,第二次走一级,一共3种方法。
输入
    输入包含若干行,每行包含一个正整数N,代表楼梯级数,1 <= N <= 30
输出
    不同的走法数,每一行输入对应一行输出
样例输入

    5
    8
    10

样例输出

    8
    34
    89

*/
#include <iostream>
using namespace std;
void back(int m,int &res){
	//回溯条件,即到了楼底了
	if(m==0){
		// 方案++
		res++;
		return;
	}
	for(int i=1;i<=2;i++){
		// 不符合条件
		if(m-i<0) continue;
		// 做选择
		back(m-i,res);
	}
}

int main(){
	int m;
	while(cin >> m){
		int res = 0;
		back(m,res);
		cout<<res<<endl;
	}
	return 0;
}

值得注意的是这里dfs还需要注意,一般我们记录所有方案的话,就需要选择和撤销选择,来维护节点的属性!

2.具体方案类

举个简单例子就是全排列。

思考一下,选择之后不撤销的话就会对其他子问题的路径记录有影响!

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
vector<vector<int> > res;
void dfs(vector<int> nums,vector<int>& track);
int main(){
	vector<int> nums;
	for(int i=1;i<=3;i++){
		nums.push_back(i);
	}
	vector<int> track;
	dfs(nums,track);
	vector<vector<int> >::iterator iter;
	for(iter=res.begin();iter!=res.end();iter++){
		vector<int> in = *iter;
		vector<int>::iterator iter2;
		for(iter2=in.begin();iter2!=in.end();iter2++){
			cout<<*iter2;
		}
		cout<<endl;
	}
}
// nums为选择,track为路径 
void dfs(vector<int> nums,vector<int>&track){
	if(track.size()==nums.size()){
		//将当前的路径加入到res 
		res.push_back(track);
		return;
	}
	
	for(int i=0;i<nums.size();i++){
		//用路径进行剪枝
		if(count(track.begin(),track.end(),nums[i])) continue;
		//选择
		track.push_back(nums[i]);
		dfs(nums,track);
		//撤销
		track.pop_back();
	}
}

再来一个李白喝酒问题

题目描述:

李白街上走,提壶去买酒,遇店加一倍,见花喝一斗”,途中,遇见5次店,见了10此花,壶中原有2斗酒,最后刚好喝完酒,要求最后遇见的是花,求可能的情况有多少种?

题解:

#include <iostream>
#include <vector>
#include <list>
using namespace std;
void dfs(int jiu,int hua,int dian);
int res = 0;
int main(){
	int jiu = 2;
	int hua = 10;
	int dian = 5;
	dfs(jiu,hua,dian); 
	cout<<res;
} 

void dfs(int jiu,int hua,int dian){
	//结束条件
	if(jiu==1&&hua==1&&dian==0){
		res++;
		return;
	}
	if(hua>0){
		dfs(jiu-1,hua-1,dian);
	}
	if(dian>0){
		dfs(jiu*2,hua,dian-1);
	}
}

这是我目前总结的经验,后续遇见其他的还会补充的!不懂的可以问我这个小菜鸡!

上一篇:P2P连接


下一篇:kinova jaco2 TrajectoryPoint