回溯算法简介:
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
代表问题:
N皇后问题,全排列问题,解数独问题等;
回溯体模板:
void backtracking(当前标记, 【其他条件1, 其他条件2】)
{
if(当前标记 == 结束条件)
{
【如果找到一个结果后就要返回,这里应该设置一个flag= 1】;
【结束后需要的操作】;
return ;
}
else
{
for (auto i:遍历范围(数度中遍历范围就是1-9, 全排列中遍历范围就是当前位置到之后的所有元素))
{
【在数独,皇后的问题中此步需要判断当前i是否可用】;
使用i;
backtrack(标记+1,【其他条件1, 其他条件2】);
if(flag == 1)return ;
还原i(以便在下一次回溯中继续使用);
}
}
}
解数独完整代码(为leetcode37题答案):
int flag = 0;
int usedr[9][10] = {0}, usedc[10][9] = {0};
void init(vector<vector<char>>& board)
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (board[i][j] != '.')
{
usedr[i][board[i][j] - '0'] = 1;
usedc[board[i][j] - '0'][j] = 1;
}
}
}
}
bool block(int time, vector<vector<char>>& board, int target)
{
int rbegin = time / 9 /3*3;
int cbegin = time % 9 /3*3;
for (int i = rbegin; i < rbegin + 3; i++)
{
for (int j = cbegin ; j < cbegin + 3; j++)
{
if (board[i][j] == target + '0')
return false;
}
}
return true;
}
void backtrack(int time, vector<vector<char>>& board)
{
if (time == 81)
flag = 1;
else
{
if (board[time/9][time%9] != '.')
backtrack(time+1, board);
else
{
for (int i = 1; i < 10; i++)
{
if (usedr[time/9][i] == 0 && usedc[i][time%9] == 0 && block(time, board, i))
{
usedr[time/9][i] = 1;
usedc[i][time%9] = 1;
board[time/9][time%9] = i + 48;
backtrack(time+1, board);
if (flag == 1) return ;
board[time/9][time%9] = '.';
usedr[time/9][i] = 0;
usedc[i][time%9] = 0;
}
}
}
}
}
void solveSudoku(vector<vector<char>>& board)
{
init(board);
backtrack(0, board);
return ;
}