搜索
深度优先搜索(回溯) dfs
枚举每个状态
修改状态
递归搜索
回溯
恢复现场
eg:排列数字
给定一个整数n,将数字1~n排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。
#include<bits/stdc++.h>
using namespace std;
const int N =10;
int all[N],n;
bool ok[N];//状态数组
void dfs(int u)
{
//边界条件,输出结果
if(u == n)
{
for(int i = 0 ; i < n ;i++)
cout<<all[i]<<" ";
cout<<endl;
return ;
}
for(int i = 1 ; i <= n ; i++)
{
if(!ok[i] )//如果没有用过
{
all[u] = i ;//改变状态
ok[i] = true;
dfs(u + 1);//递归搜索 回溯
ok[i] = false; //恢复现场
}
}
}
int main()
{
cin>>n;
dfs(0);
return 0;
}
eg:n-皇后问题
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
int ok[N], dg[N*2], udg[N * 2], n ;
//状态数组 ok是列,dg是对角线,udg反对角线
char all[N][N];
//一排为单位搜索
//u代表第几行,i代表第几列
void dfs(int u)
{
//边界,该输出了
if (u == n )
{
for(int i = 0 ; i < n ; i ++)
{
for(int j = 0 ; j < n ; j ++)
cout<<all[i][j];
cout<<endl;
}
cout<<endl;
return ;
}
for(int i = 0 ; i < n ; i++)
{
//对角线:行+ 列 ,反对角线:列- 行 + n保证为正数
if( ok[i] == 0 && dg[i + u ] == 0 && udg[n - u + i ] == 0)
{
//如果可以
all[u][i] = 'Q';
ok[i] = dg[i + u ] = udg[n - u + i ] = 1 ;
//递归搜索
dfs(u + 1 );
//恢复现场
ok[i] = dg[i + u ] = udg[n - u + i ] = 0 ;
all[u][i] = '.';
}
}
}
int main()
{
cin>>n;
//初始化
for(int i = 0 ; i < n ; i++)
for(int j = 0 ; j < n ; j ++)
all[i][j] = '.';
dfs(0);
return 0;
}
广度优先搜索(bfs)
队列实现
记录访问状态
eg:走迷宫
#include <bits/stdc++.h>
using namespace std;
typedef pair<int , int> PII;
const int N =110;
int p[N][N], re[N][N],n ,m ;
int bfs()
{
queue<PII> q;//定义一个队列
//初始化 0 0 点的距离为0 ,将0 , 0 点放入队列
re[0][0] = 0;
q.push({0 , 0});
//位置偏移量,上右下左
int dx[] = {-1 , 0 , 1 , 0} ,dy[] = {0 , 1 , 0 , -1};
//当q不为空,一直循环
while(q.size())
{
auto t = q.front();//从队列的头部弹出第一个值
q.pop();//删除
//上右下左搜索
for(int i = 0 ; i < 4 ; i ++)
{
//搜索的坐标
int x = t.first + dx[i] ,y = t.second + dy[i];
//满足条件,没有出界,没有走过
if(x >= 0 && x < n && y >=0 && y < m && p[x][y] == 0 && re[x][y] ==-1)
{
//将坐标放入队列中
q.push({x,y});
//改变记录距离的数组 上一个位置的值+1
re[x][y] = re[t.first][t.second] + 1;
//将这个位置改变状态
p[x][y] =1;
}
}
}
//返回 n - 1 , m - 1 的距离
return re[n - 1][m -1];
}
int main()
{
cin>>n >> m;
for(int i = 0 ; i < n ; i ++)
{
for(int j = 0 ; j < m ; j ++ )
{
cin>>p[i][j];
re[i][j] = -1;
}
}
cout<<bfs();
return 0;
}
eg:八数码
#include <iostream>
#include <queue>
#include <unordered_map>
using namespace std;
int bfs(string all)
{
//定义一个字符串队列,哈希表存状态
queue<string> q;
unordered_map<string ,int >d;
//将最开始的状态放入队列,哈希表中最开始的状态为0
q.push(all);
d[all]= 0 ;
//最终的状态
string end= "12345678x";
//位置偏移量,上右下左
int dx[] = {-1 , 0 , 1 , 0 } , dy[] = {0 ,1 , 0 , -1};
//队列不为空就一直循环
while(q.size())
{
/从对头弹出,删除对头
auto t = q.front();
q.pop();
//t和最终状态一样就输出
if(t == end) return d[t];
//从一维变成二维坐标,一维坐标整除3是行,取余3是列
int dis = d[t] ;
int k = t.find('x');
int x = k / 3 , y = k % 3;
//上右下左搜索
for(int i = 0 ; i < 4 ; i++)
{
//搜索的坐标
int a = x + dx[i] , b = y + dy[i];
//判断是否出界
if(a >= 0 && a < 3 && b >= 0 && b < 3 )
{
//交换字符串中的字符
swap(t[k] , t[a* 3 + b]);
//判断是否走过
if(!d[t])
{
//如果没有,加到哈希表和队列中
d[t] = dis +1;
q.push(t);
}
//把状态恢复
swap(t[k] , t[a * 3 + b]);
}
}
}
return -1;
}
int main()
{
string all;
//读入字符串
for(int i = 0 ; i <9 ; i ++)
{
char c;
cin>>c;
all+=c;
}
cout<<bfs(all);
return 0;
}