万恶之源
P1434 [SHOI2002]滑雪

做法

这道题就是在一个二维的序列中,求最长的一条一维的递减子序列的长度。这道题用深搜做会很方便,不撞南墙不回头,对与任意一点只要周围有高度更小的点就一直深搜下去,搜索的层数即是其最大长度,最后输出各个点的最大长度的最大值即可。

需要注意的点

  1. 如果直接像上面那要做肯定TLE无疑,考虑到上述做法会有很多冗余的重复访问,可以将搜索记忆化,即记忆化搜索

我们可以用d[i][j]表示从点(i,j)出发能走的最长路
这样当每个点第二次被访问到的时候可以直接使用d[i][j]而不是进一步搜索

int dfs(int x,int y){//状态是当前遍历到第几个点,目标是遍历所有点找出最长路 
	if (dis[x][y]>1)	return dis[x][y];
  1. 这里同样和马的遍历一样,需要判断边界,注意行和列的区分!!!
bool check(int x,int y){
	if (x<1 || y<1) return false;
	if (x>r || y>c) return false;//这里不能是 x>c || y>r,辨析好变量的概念,养成好习惯; 
	return true;
}
正题——DFS

框架为王

void dfs(int st){//这里要明确状态和目标 
	if (/*退出的条件,一般就是最底层的状态*/){
		//某些处理
		return; 
	}
	//一些预处理
	for(/*遍历条件*/){//遍历子节点
		//遍历前的预处理
		dfs(/*进入下一层*/);
		//回溯处理 
	} 
	return; 
}

特点

  1. 不撞南墙不回头

其搜索方式为,在某个状态A,找到一个可以由此状态转移到的状态B,然后转移到状态B,遍历完B所有的后续状态后,返回状态A,再寻找A的另一个可转移状态C,如此往复,直至所有状态被遍历完

  1. 复杂度往往很高,这时候就需要进行剪枝

有些状态是一定搜不到目标状态的,这个时候我们就没必要搜索其后

这个过程就叫做剪枝
剪枝通常分为两种:可行性剪枝和最优化剪枝

因为剪枝能够防止遍历无用的状态,所以搜索也可以跑过一些数据范围较大的题目,甚至暴力碾标算

  1. 回溯处理很重要!!!