文章目录
回溯算法定义
回溯法是一种系统搜索问题解空间的方法。为了实现回溯,需要给问题定义一个解空间。说到底它是一种搜索算法。只是这里的搜索是在一个叫做解空间的地方搜索。要实现回溯,需要两点1搜索,2解空间。
先看什么是解空间。就是形如数组的一个向量[a1,a2,…,an]。这个向量的每个元素都是问题的部分解,只有当这个数组的每一个元素都填满(得到全部解)的时候,才表明这个问题得到了解答。
再看搜索。最简单的就是for循环,上面的向量有n个维度,因此就是n个for循环。但是如果n是100?n是100000?那么如何回溯?因此我们需要一种全新的书写回溯的方法。形如:
void backtrack(int i,int n,other parameters)
{
if (some condition) {
// 剪枝
return;
}
if ( i == n) {
//get one answer
record answer;
return;
}
//下面的意思是求解空间第i个位置上的下一个解
for (next ans in position i of solution space) {
push(ans);
backtrack(i+1,n,other parameters);
pop(ans);
}
}
举例
n皇后(LeeCode 51题)
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击,同一行,同一列或者对角线上的皇后可互相攻击(正对角线上行列之和为常数,负对角线上行列之差为常数)。每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
#define MAX_NUM 2000
int valid(int *solution, int row)
{
for (int i = 0; i < row - 1; i++) {
if ((solution[i] == solution[row-1]) ||
(i + solution[i]) == (row-1 + solution[row-1]) ||
(i - solution[i]) == (row-1 - solution[row-1])) {
return 0;
}
}
return 1;
}
void traceBack(int n, int row, int *solution, int **allSolu, int *soluNum)
{
/*剪枝*/
if (!valid(solution, row)) {
return;
}
/*获得一个解*/
if (row == n) {
int *tmp = malloc(sizeof(int) * n);
memcpy(tmp, solution, sizeof(int) * n);
allSolu[*soluNum] = tmp;
(*soluNum)++;
return;
}
/*遍历求解空间第i个位置上的下一个解*/
for (int i = 0; i < n; i++) {
solution[row] = i;
traceBack(n, row + 1, solution, allSolu, soluNum);
}
}
char *** solveNQueens(int n, int* returnSize, int** returnColumnSizes){
int *solution = malloc(sizeof(int) * n);
int **allSolu = malloc(sizeof(int*) * MAX_NUM);
int soluNum;
char *** rtn;
traceBack(n, 0, solution, allSolu, &soluNum);
rtn = malloc(sizeof(char**) * soluNum);
for (int i = 0; i < soluNum; i++) {
rtn[i] = malloc(sizeof(char*) * n);
for (int j = 0; j < n; j++) {
rtn[i][j] = malloc(sizeof(char) * (n + 1));
memset(&rtn[i][j][0], '.', n);
rtn[i][j][allSolu[i][j]] = 'Q';
rtn[i][j][n] = 0;
}
}
*returnSize = soluNum;
*returnColumnSizes = malloc(sizeof(int) * soluNum);
for (int j = 0; j< soluNum; j++){
(*returnColumnSizes)[j] = n;
}
return rtn;
}