深搜(入门篇) 分类: 回溯 2011-02-17 10:15 400人阅读 评论(0) 收藏 举报 学习深搜有一些时间了,个人感觉深搜满足一定的形式: [cpp] view plaincopy void dfs (int a,……) //参数个数不确定 { if (……) //边界条件 { …… } else { dfs(a+1,……); } } 若是再具体一些的话: [cpp] view plaincopy void dfs (int a,……) { if (……) //边界条件 { …… } else { for () //横向遍历解答树 { dfs(a+1,……) } } } 解答树的模型、边界条件的判断和剪枝技巧是很重要的; 先来几个经典实例: 1.整数拆分: 例如: 3 = 1 + 1 + 1; 3 = 1 + 2; 3 = 3; [cpp] view plaincopy #include <iostream> #include <cstdio> using namespace std; #define MAX 30 int res[MAX], //保存结果 N, count; //记录结果总数 void print(int cur) //打印结果 { printf("No %-3d: %d=",count,res[0]); for (int i=1; i<cur; ++i) //结果范围是[1,cur-1] { printf("%3d",res[i]); } printf("/n"); } void split(int cur, int remain) { int k; //剪枝用,可以避免重复情况 if (remain == 0) //若剩余数值为0,拆分完毕 { ++count; print(cur); } else { k = res[cur-1]; if (k > remain) { k = remain; } for (int i=1; i<=k; ++i) { res[cur] = i; split(cur+1,remain-i); } } } int main() { while (scanf("%d",&N) != EOF) { count = 0; res[0] = N; split(1,N); } return 0; } 2.组合问题: 传送门: http://blog.csdn.net/dpdldh/archive/2011/02/17/6190723.aspx 3.N的全排列: [cpp] view plaincopy #include <iostream> #include <cstdio> #include <cstring> using namespace std; #define MAX 30 int res[MAX], //存放排列数 vis[MAX], //标记数字是否被访问 N, //从1~N中排列 count; //情况总数 void print() { printf("No %-3d: %3d",count++,res[1]); for (int i=2; i<=N; ++i) { printf("%3d",res[i]); } printf("/n"); } void permutation(int cur) { if (cur > N) { print(); } else { for (int i=1; i<=N; ++i) { if (!vis[i]) { vis[i] = 1; res[cur] = i; permutation(cur+1); vis[i] = 0; //这一步不要忘了!! } } } } int main() { while (scanf("%d",&N) != EOF) { count = 0; memset(vis,0,sizeof(vis)); permutation(1); } return 0; } 4.N皇后 传送门:http://blog.csdn.net/dpdldh/archive/2011/02/16/6188561.aspx 以上是一些经典的问题,下面来一些简单的题目: 1.TOJ 1002 (全排列问题) http://blog.csdn.net/dpdldh/archive/2011/02/17/6190887.aspx 2.TOJ 1017 (石子归并) http://blog.csdn.net/dpdldh/archive/2011/02/17/6190891.aspx 3.HDU 1016 (素数环) http://blog.csdn.net/dpdldh/archive/2011/02/11/6178456.aspx