在acwing(一个很不错的算法学习平台)学习算法与数据结构,有时候一些题目要花费很长时间去想,下面写写我在学习过程中的思考和心得。也不知道能不能坚持写下去。自己的想法难免有不准确的地方,这里欢迎各位大佬指正。
DFS
原题链接:排列数字 - AcWing
最关键是要理解回溯与恢复原状态的两个操作。
回溯:可以想象有一颗递归树,每次生成一个符合题意的结果后或者该情况不符合题意,就会返回到它的上一个节点。
恢复原状态:设置一个状态数组st[N],用来表示该位置是否可以存放值。0代表可以存放,1代表不能存放。每一次回溯过后都要执行恢复的操作。
排列数字
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10000;
int p[N], st[N], n;
void dfs(int u)
{
if(u == n)
{
for (int i = 0; i < n; i ++ ) cout<<p[i]<<' ';
cout<<endl;
return;
}
for(int i = 1; i <= n; i ++)
{
if(st[i] == 0)
{
p[u] = i;
st[i] = 1;
dfs(u+1); //进行递归树的下一层
st[i] = 0; //回溯到上一个节点,要恢复到原状态
}
}
}
int main()
{
cin>>n;
dfs(0);
return 0;
}
n-皇后问题:
n-皇后问题本质上就是排列数字的问题,有点抽象,用文字不好解释,直接上草图。然后就是解决如何表示对角线的问题了,我们可以把n*n矩阵抽象成一个平面坐标系,同一条对角线一定会过同一个b (y=x+b)。所以我们可以用截距b来表示对角线。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
int col[N], dg[N], udg[N], n, x;
char p[N][N];
// col列:记录该列的使用状态
dg对角线,udg反对角线:记录该条对角线的使用状态
0表示未被使用
// p[N][N]用来存结果
void dfs(int u)
{
if( u == n) //此时已经搜索了n行,输出结果
{
for (int i = 0; i < n; i ++ ) cout<<p[i]<<endl;
cout<<endl;
return;
}
int x = u; //搜索u这一行
for(int y = 0; y < n; y ++) //搜索列
{
//判断该位置能否放置'Q',0表示未被使用
if(col[y] == 0 && dg[y + x] == 0 && udg[y - x + n] == 0)
{
p[x][y] = 'Q';
col[y] = dg[y+x] = udg[y-x+n] = 1; //更新位置状态
dfs(x + 1); //搜索下一行
p[x][y] = '.'; //恢复原状态
col[y] = dg[y+x] = udg[y-x+n] = 0;
}
}
}
int main()
{
cin>>n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
p[i][j] = '.';
dfs(0);
}