回溯

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

迷宫问题
迷宫问题
• 问题描述:给一张个迷宫,问能否从起点走到终点,只能往上下左右 走,不能斜着走 • INPUT: • 每组第一行两个正整数,分别为n和m • 表示n这个迷宫有n行m列(0<n,m<10) • 接着是n行m列, • '#'表示路 • ‘*’表示墙 • ‘S’表示起点 • ‘T’表示终点
更通用的递归解法算法框架
• int a[n]; • try(int i)
for(j = 下界; j <= 上界; j=j+1) // 枚举i所有可能的路径 { if(fun(j)) // 满足限界函数和约束条件 { a[i] = j; ... // 其他操作 try(i+1); 回溯前的清理工作(如a[i]置空值等); } } } }
回溯算法
——崔振宇
回溯算法的定义
• 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝 试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯” 返回,尝试别的路径。 • 回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。 但当探索到某一步时,发现原先选择并不优或达不到目标,就退 回一步重新选择,这种走不通就退回再走的技术为回溯法,而满 足回溯条件的某个状态的点称为“回溯点”。
void dfs(int x,int y){ visit[x][y]=1; if(c[x][y]=='T'){ re=1; return; } for(int i=0;i<4;i++){ int x1=x+dx[i]; int y1=y+dy[i];
if(x1>=0&&y1>=0&&x1<n&&y1<m&&visit[x1][y1]==0&&c[x1][y1]!='*') dfs(x1,y1); } }
源代码(骑士游历高级解法)
#include <iostream> #include <cstring> using namespace std; #define MAXN 111 long long dp[MAXN][MAXN]; int main() { int n, m, x1, y1, x2, y2; cin >> n >> m; cin >> x1 >> y1 >> x2 >> y2; dp[x1][y1] = 1; for(int i=x1+1; i<=x2; i++) { for(int j=1; j<=n; j++) { dp[i][j]=dp[i-2][j-1]+dp[i-1][j-2]+dp[i-1][j+2]+dp[i-2][j+1]; } } cout << dp[x2][y2]; return 0; }
int a[n],i; 初始化数组a[]; i = 1; while (i>0(有路可走) and (未达到目标)) // 还未回溯到头 { if(i > n) // 搜索到叶结点 { 搜索到一个解,输出; } else // 处理第i个元素 { …… } } a[i]第一个可能的值; while(a[i]在不满足约束条件且在搜索空间内) { a[i]下一个可能的值; } if(a[i]在搜索空间内) { 标识占用的资源; i = i+1; // 扩展下一个结点 } else { 清理所占的状态空间; // 回溯 i = i –1; }
N个数的全排列
int main() { int n; while(scanf("%d",&n)!=EOF) { dfs(n,0); } return 0; }
int use[N]; int num[N]; void dfs(int n,int t) { if(t==n) { for(int i=0; i<n;i++) printf("%d ",num[i]); printf("\n"); } //return ; for(int i=1; i<=n; i++) { if(use[i]==0) { use[i] = 1; num[t]=i; dfs(n,t+1); use[i] = 0; } } }
用回溯算法解决问题的一般步骤为:
• 1、定义一个解空间,它包含问题的解。 • 2、利用适于搜索的方法组织解空间。 • 3、利用深度优先法搜索解空间。 • 4、利用限界函数避免移动到不可能产生解的子空间。

回溯三要素
• 1) 解空间:该空包含问题的解 • 2) 约束条件 • 3) 状态树
非递归解法算法框架
骑士游历问题
• 有一个n*m棋盘 • 输出N,⑴马走日字 • ⑵码只能向右走 • 求出从起始点到棋盘最右边的所有路径
骑士游历问题
//整体采用一个二维数组来存储 void knight(int i,int j) //其中i和j是当前扩展结点的坐标 { if(是目标结点) 输出路径; else for(当前节点的另一个子结点) { 设置下一个扩展结点; if(符合约束条件) knight(下一个结点的坐标); 回溯; } }
• 要素二:约束条件 • 不同行:数组x的下标保证不重复 • 不同列:x[i]<>x[j] (i<=I,j<=n;i<>j) • 不同对角线:abs(x[i]-x[j])<>abs(i-j) • 填到第K行时,就与前1~(K-1)行都进行比较
K=0
过程:进入新一行, 该行上按顺序逐个 格子尝试,直到能 放为止(不冲突、 不越界) 算法描述: 1. 产生一种新放法 2. 冲突,继续找,直到找到不冲 突----不超范围 3. if 不冲突 then k<nk+1 k=n一组解 4. if 冲突 then 回溯
K=1
* **
K=2
* * *****
回溯
*
*
出解后 可以继 续刚才 的做法
K=3
* * * * ** * * * **** * * *
回溯
*
*
* *
*
K=4
*
* *
*
源代码
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> int main() { num = 8; sum = 0; x = new int[num+1]; for(int i= 0;i<=num;i++) x[i] = 0; backtrack(1); cout<<"方案共有"<<sum; return 0; }
using namespace std;
static int num; static int *x; static int sum;
源代码
void backtrack(int t) { if(t>num) //num为皇后的数目 { sum++;//sum为所有的可行的解 for(int m = 1; m<num; m++) { cout<<x[m];//这一行用输出当递归到叶节点的时候, 一个可行解 } cout<<endl; } else for(int i = 1; i<=num; i++) { x[t] = i; if(place(t)) backtrack(t+1);//此处的place函数用来进行 我们上面所说的条件的判断,如果成立,进入下一级递归 } } bool place(int k) { for(int j = 1; j<k; j++) if(abs(x[k] - x[j]) == abs(k-j)||x[j] == x[k]) return false; return true; }
Output:每组测试数据输出一个结果,如果能从S走到T,输出“YES”,否则输出“NO”
迷宫问题
#include <cstdio> #include <cstring> using namespace std; const int dx[]={-1,0,1,0}; const int dy[]={0,1,0,-1}; char c[10][10];//定义字符数组 int visit[10][10];//定义访问数组,访问标记为1,未访问 标记为0 int n,m,re;//字符数组的行数,列数和返回值 int main() { while(scanf("%d%d",&n,&m)!=EOF){ memset(c,'\0',sizeof(c)); memset(visit,0,sizeof(visit)); re=0; for(int i=0;i<n;i++){ getchar(); scanf("%s",c+i); } int p,q; //找出起点的坐标 for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(c[i][j]=='S'){ p=i; q=j; break; } } } dfs(p,q); if(re==1) printf("YES\n"); else printf("NO\n"); } return 0; }
• {
• • • • { if(i>n) 输出结果; else
八皇后问题
• 在一个n*n的国际象棋棋盘上放置n个皇后,使得它们中任意2个 之间都不互相“攻击”,即任意2个皇后不可在同行、同列、同 斜线上。 • 输出N,⑴求N皇后问题的一种放法; • ⑵求N皇后问题的所有放法
• 分析: • N=4时,右图是一组解 • 要素一: 解空间 • 一般想法:利用二维数组,用[i,j]确定一个皇后位置! • 优化:利用约束条件,只需一维数组即可。 x[i]:i表示第i行皇后 x[i]表示第i行上皇后放第几列
相关文档
最新文档