P1434 滑雪(DFS)笔记
万恶之源
P1434 [SHOI2002]滑雪
做法
这道题就是在一个二维的序列中,求最长的一条一维的递减子序列的长度。这道题用深搜做会很方便,不撞南墙不回头,对与任意一点只要周围有高度更小的点就一直深搜下去,搜索的层数即是其最大长度,最后输出各个点的最大长度的最大值即可。
需要注意的点
- 如果直接像上面那要做肯定TLE无疑,考虑到上述做法会有很多冗余的重复访问,可以将搜索记忆化,即记忆化搜索
我们可以用d[i][j]表示从点(i,j)出发能走的最长路
这样当每个点第二次被访问到的时候可以直接使用d[i][j]而不是进一步搜索
int dfs(int x,int y){//状态是当前遍历到第几个点,目标是遍历所有点找出最长路
if (dis[x][y]>1) return dis[x][y];
- 这里同样和马的遍历一样,需要判断边界,注意行和列的区分!!!
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;
}
特点
- 不撞南墙不回头
其搜索方式为,在某个状态A,找到一个可以由此状态转移到的状态B,然后转移到状态B,遍历完B所有的后续状态后,返回状态A,再寻找A的另一个可转移状态C,如此往复,直至所有状态被遍历完
- 复杂度往往很高,这时候就需要进行剪枝
有些状态是一定搜不到目标状态的,这个时候我们就没必要搜索其后
这个过程就叫做剪枝
剪枝通常分为两种:可行性剪枝和最优化剪枝
因为剪枝能够防止遍历无用的状态,所以搜索也可以跑过一些数据范围较大的题目,甚至暴力碾标算
- 回溯处理很重要!!!