相信大家都学过枚举算法叭,如果学过的话,就继续跟蒟蒻君往下学吧!
首先,请大家看一道题~
题目1:全排列
#include
using namespace std;
bool vis[11]; // 假设n最大为10,vis[i]表示第i个数在当前这个排列中是否被用过
int n, a[11]; // 表当前排列的结果
void dfs(int stp) { // stp是step的缩写,表示现在已经枚举到了第几步(所谓的第几层循环)
if (stp == n + 1) { // 当n层循环都枚举完后,输出当前结果并且结束dfs函数
for (int i = 1; i <= n; ++i) {
cout << a[i] << ' ';
}
cout << '\n'; // 不要忘记排列之间要用换行隔开
return ;
}
for (int i = 1; i <= n; ++i) { // 枚举所有数,找到符合条件的数(没有被用过),然后放到当前数位上
if (!vis[i]) {
vis[i] = 1; a[stp] = i; // 先放到当前数位上,继续枚举,然后尝试其他数,这样的过程就是一个回溯算法
dfs(stp + 1);
vis[i] = 0;
}
}
}
int main() {
cin >> n;
dfs(1); // 从第1个数开始枚举
return 0;
}
注释已经很清楚了,蒟蒻君就不再讲这道题啦。
蒟蒻君温馨提示:在搜索枚举的过程中,我们可以根据题目性质,对过程进行剪枝优化(在后几节课会讲)。但是在大部分题目中,dfs的时间复杂度会超,所以在搜索前,我们很有必要确定问题状态的总数。
下面给大家出一道练习题~
题目2:烤鸡
#include
using namespace std;
int n, ans1, ans2[10000][10], arr[10], sum;
void dfs(int stp, int now) {
// 请继续完成这个函数~
}
int main() {
cin >> n; dfs(1, 0);
cout << ans1 << '\n';
for (int i = 1; i <= ans1; ++i) {
for (int j = 1; j <= 10; ++j) {
cout << ans2[i][j] << ' ';
}
puts("");
}
return 0;
}
#include
using namespace std;
int n, ans1, ans2[10000][10], arr[10], sum;
void dfs(int stp, int now) {
if (stp > 10) {
if (now == n) {
++ans1;
for (int i = 1; i <= 10; ++i) {
ans2[ans1][i] = arr[i];
}
}
return ;
}
for (int i = 1; i <= 3; ++i) {
if (now + i > n) {
break;
}
arr[stp] = i;
dfs(stp + 1, now + i);
arr[stp] = 0;
}
}
int main() {
cin >> n; dfs(1, 0);
cout << ans1 << '\n';
for (int i = 1; i <= ans1; ++i) {
for (int j = 1; j <= 10; ++j) {
cout << ans2[i][j] << ' ';
}
puts("");
}
return 0;
}
学到这里,大家应该已经发现一点规律了~
给大家列出基本的dfs框架~
void dfs(目前状态) {
判断边界
尝试每一种可能,跳出可以继续的 {
继续搜索,尝试下一步
}
}
当然,枚举不一定非要用for循环滴!这里给大家一个例子,希望大家能融会贯通~
题目3:n阶幻方
#include
using namespace std;
int n, a[45][45];
void dfs(int x, int y, int now) { // 目前坐标和下一步要填的数
if (now > n * n) { // 所有数都填完了,输出,然后结束dfs函数
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cout << a[i][j] << ' ';
}
cout << '\n';
}
return ;
}
// 直接模拟即可
if (x == 1 && y != n) {
a[n][y + 1] = now;
dfs(n, y + 1, now + 1);
} else if (y == n && x != 1) {
a[x - 1][1] = now;
dfs(x - 1, 1, now + 1);
} else if (x == 1 && y == n) {
a[x + 1][y] = now;
dfs(x + 1, y, now + 1);
} else {
if (a[x - 1][y + 1] == 0) {
a[x - 1][y + 1] = now;
dfs(x - 1, y + 1, now + 1);
} else {
a[x + 1][y] = now;
dfs(x + 1, y, now + 1);
}
}
}
int main() {
cin >> n;
a[1][(n + 1) / 2] = 1; // 特殊处理1
dfs(1, (n + 1) / 2, 2);
return 0;
}
看到这里,大家是不是已经会处理基本dfs的题目了?如果大家觉得有帮助的话,就继续期待蒟蒻君的第二篇吧!