回溯初级
回溯算法
一种带有条件限制的穷举算法
1. 常用场景
在某种限制下求可行方案数
或最优解
。
2. 算法思想
在满足条件的情况下选择一个方法
/路径
进行运算,运算完毕后回到选择之前,换一种选择继续运算,直至无选择。
3. 模板
回溯算法往往和递归密切相关,一般模板如下:
void dfs() {
if (terminating condition)
for (alternative) {
dfs();
recover
}
}
4. 经典例题
- N皇后
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 8;
int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
int ans = 0;
vector<vector<int>> board(N, vector<int>(N, 0));
void use(int x, int y) {
int xx, yy;
for (int i = 0; i < N; i++) {
for (int j = 0; j < 8; j++) {
xx = x + i * dx[j];
yy = y + i * dy[j];
if (xx >= 0 && xx < N && yy >= 0 && yy < N) {
board[xx][yy] = 1;
}
}
}
}
void dfs(int x, int t) {
if (t == N) {
ans++;
return;
}
vector<vector<int>> tmp = board;
for (int i = 0; i < N; i++) {
if (!board[x][i]) {
use(x, i);
dfs(x + 1, t + 1);
}
board = tmp;
}
}
int main() {
dfs(0, 0);
cout << ans << endl;
return 0;
}
- POJ1321 棋盘问题
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 10;
int n, k, ans;
int vis[10];
char board[N][N];
void dfs(int x, int t) {
if (t == k) {
ans++;
return;
}
if (x == n)
return;
for (int i = 0; i < n; i++) {
if (vis[i] || board[x][i] != '#')
continue;
vis[i] = 1;
dfs(x + 1, t + 1);
vis[i] = 0;
}
dfs(x + 1, t);
}
int main() {
while (scanf("%d %d",&n,&k)) {
if (n == -1 && k == -1)
break;
for (int i = 0; i < n; i++)
scanf("%s", board[i]);
ans = 0;
dfs(0, 0);
printf("%d\n", ans);
}
return 0;
}