一、动态回溯相关
1.动态回溯:
(寻路算法 深度寻路算法)
2.动态回溯算法思想:
① 针对问题来解空间: 根据实际需求用不同方式来描述
深度寻路算法: 要找到起点到终点的路径 二维数组来描述地图
② 确定易于搜索的解空间结构,并构造相应的判断函数
③ 用深度优先搜索的方式来解决问题,并要有合适的回溯方式(栈)动态回溯 == 问题的解空间 + 深度优先搜索 + 判断结果的结构 + 回溯
3.动态回溯一般用来解决哪些问题:
① 寻路 ②货物装载 ③0-1背包问题 ④图的着色问题(涂格子)
⑤电路排版问题 ⑥ 旅行者售后员问题 ⑦N皇后问题
二、典例----N皇后问题分析
1.问题规则+算法流程分析
8皇后问题: 国际象棋棋盘 在任意两个皇后不能互相触及的前提下 有多少种摆法
1 问题的解空间 : 二维数组
2 深度优先搜索 : 递归 一个个去摆 摆了N个皇后结束
3 判断结果 : 判断能不能摆 数量是否达标
4 回溯 : 给二维数组元素赋值 为1 表示摆放好了 赋值为0 就是回退
2.代码实现
// N皇后问题.cpp : 定义控制台应用程序的入口点。
//
#include<cstdio>
#define TEST 1
#define N 4
//用来记录有多少种解法
int cnt = 0;
//遍历整个棋盘
void travel(int Q[N][N]);
//N皇后问题
void Queen(int j, int Q[N][N]);
//判断 i j 位置是否能放皇后 如果能 返回true 否则 返回false
bool isOkPos(int i, int j, int Q[N][N]);
int main()
{
int Q[N][N] = { 0 };//0表示没有放皇后 1表示放了皇后
Queen(0, Q);
printf("解法种数为:%d\n", cnt);
return 0;
}
//N皇后问题
void Queen(int j, int Q[N][N])
{
if (N == j)
{//N个皇后都已经放置好了
#if TEST
travel(Q);//遍历整个地图
#endif
cnt++;
return;
}
for (int i = 0; i < N; i++)
{//y坐标
if (isOkPos(i, j, Q))
{//能放
Q[i][j] = 1;//放
Queen(j + 1, Q);//放下一个
Q[i][j] = 0;//回溯
}
}
}
//遍历整个棋盘
void travel(int Q[N][N])
{
printf("-------------------------------------------\n");
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
printf("%d ", Q[i][j]);
}
printf("\n");
}
printf("-------------------------------------------\n");
}
//判断 i j 位置是否能放皇后 如果能 返回true 否则 返回false
bool isOkPos(int i, int j, int Q[N][N])
{
int s;//s i 垂直 y轴
int t;//t j 水平 x轴
//横向判断
for (s = i, t = 0; t < N; t++)
{
if (Q[s][t] == 1 && j != t) return false;
}
//纵向判断
for (t = j, s = 0; s < N; s++)
{
if (Q[s][t] == 1 && s != i) return false;
}
//左上
for (t = j - 1, s = i - 1; s >= 0 && t >= 0; s--, t--)
{
if (Q[s][t] == 1) return false;
}
//左下
for (t = j - 1, s = i + 1; s < N && t >= 0; s++, t--)
{
if (Q[s][t] == 1) return false;
}
//右上
for (t = j + 1, s = i - 1; s >=0 && t < N; s--, t++)
{
if (Q[s][t] == 1) return false;
}
//右下
for (t = j + 1, s = i + 1; s < N && t < N; s++, t++)
{
if (Q[s][t] == 1) return false;
}
return true;
}