DFS深度搜索算法实现深度探究解析-以POJ 1040为例
本人开园第一天,打算主要发表算法、编程及技术面试题等相关内容,还望各大牛多多指教!
DFS深度搜索算法实现深度探究解析-以POJ 1040为例
#include <iostream> #include <cstdlib> #include <algorithm> using namespace std; #define maxm 23 #define maxn 8 int cap, n, m; int ans; int ocount; int down[maxn]; struct Order{ int s, e, p; }order[maxm]; int max(int a,int b){ return a>b?a:b; } bool operator < (const Order &a, const Order &b){ if (a.s == b.s) return a.e < b.e; return a.s < b.s; } void dfs(int i, int p, int money){ if (i == m){ ans = max(ans, money); return; } if (i > 0) for (int j = order[i - 1].s + 1; j <= order[i].s; j++) p -= down[j]; if (p + order[i].p <= cap) { down[order[i].e] += order[i].p; //down[i]表示i号车站有多少人下车 dfs(i + 1, p + order[i].p, money + order[i].p * (order[i].e - order[i].s)); down[order[i].e] -= order[i].p; } dfs(i + 1, p, money); } int main(){ int i; while(cin>>cap>>n>>m,cap||n||m){ for(i=0;i<m;i++){ scanf("%d%d%d", &order[i].s, &order[i].e, &order[i].p); } sort(order,order+m); ans = 0; dfs(0,0,0); printf("%d\n",ans); } return 0; }
本题DFS算法实现深度解析:
1、 对order数组排序,使得票的始发站升序排练,当始发站相同时,使得终点站升序排列,这样便于统计每张票的始发站处下车的人数。
2、 DFS递归函数返回有两种情况:其一是i==m时该条路径搜索结束返回结果到原始调用处;其二是执行到DFS末尾返回,也是返回到调用该次DFS函数处。注意区分34行与37行调用DFS函数的不同,开始选择第1、2、3票搜索路径的DFS函数调用情况如下图所示
:
第34行的DFS调用是考虑选择第i张票,继续深度搜索;第37行的DFS调用是考虑不选择第i张票(可能由于选第i张票超过了火车容量限制或者是前面的搜索选择完毕回溯)调用的地方不同,自然dfs函数返回的地方也不同。
通过本题的分析,总结经验如下:
算法学习最忌讳粗枝大叶,很多看似思想简单的算法实现成代码运行就有很多新的难题,比如深度搜索DFS的实现,有以下关键点:
1、由于搜索过程高度重复化,一般写成递归函数,DFS函数里面写明返回条件,不同情况下不同的递归调用条件。
2、 DFS函数的构造一般有一个变量记录当前搜索的位置(如本题中i记录了当前搜索到了第几张票的选择),另外若干变量保存需要一直维护状态变量(如本题中的p记录了当前火车上的人数,money记录了当前选择方案下的总钱数)
3、 DFS发生回溯的时候,要注意恢复原来状态变量的值(又叫“恢复现场”),比如第35行 down[order[i].e] -=order[i].p; 这里是由于前面考虑选择第i张票的搜索路径已经搜索完毕,那么下面考虑不选择第i张票,恢复下车人数数组down的状态到不选第i张票的情况,在第37行直接去考察第i+1张票的选择情况。
最后,对于调用及执行情况比较复杂的代码,用好VC等IDE单步调试,观察callback、watch等窗口中函数调用、关键变量值的变化是很重要的研究途径,调试工具要充分利用。有必要学习一下重要的调试技巧,对于加深对程序的理解有好处。