介绍
搜索可以说是万能解题方法,在解空间中搜索满足条件的解。分为深度优先搜索(DFS)和广度优先搜索(BFS)
深度优先搜索
深度优先搜索一般和递归回溯结合使用,朝着某个方向搜索到底,然后不断变换方向。在这过程中必须设定一个指针,指向你搜索到了那一层,以此来判断是否到了叶子节点。必须掌握模板题,对于不同题目在模板题代码基础上进行修改。一般与DFS结合的题目有以下几个内容
DFS与解的个数
八皇后问题就是这类问题的代表,在解空间中搜索所有满足条件的解。
在搜索过程中要记录搜索的路径,不能重复搜索相同的路径,对于不同的路径在搜索到叶结点的时候说明找到了一个新的解,方案数+1。一般在搜索过程中添加剪枝。
代表题
https://www.luogu.com.cn/problem/P1219
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 20;
int n;
int ans;
int x[maxn];
bool vis[3][maxn + 10];
int loop = 3;
void dfs(int cur){
if(cur == n){
ans++;
if(loop > 0){
for(int i=0;i<n;i++){
printf("%d ",x[i] + 1);
}
printf("\n");
}
loop--;
return;
}
for(int i=0;i<n;i++){
if(!vis[0][i] && !vis[1][cur + i] && !vis[2][cur-i+n]){
x[cur] = i;
vis[0][i] = vis[1][cur + i] = vis[2][cur-i+n] = 1;
dfs(cur + 1);
vis[0][i] = vis[1][cur + i] = vis[2][cur-i+n] = 0;
}
}
}
int main(){
cin>>n;
dfs(0);
cout<<ans<<endl;
return 0;
}
DFS与子集
搜索过程中,对于一个集合中的每一个元素,可以选取它,也可以不选取它。这样就产生了另一类子集问题。
在这类问题中,搜索往往包含了选取元素和不选取元素的情况。有的问题要求选择出固定的几个元素出来,有的要求你选择出满足某种条件子集(不固定元素个数)。两种情况的区别在代码上体现就是搜所过的元素(搜索的时候可能没有选取改元素)是否还要向子集中添加
搜索过的内容继续向子集中添加
https://www.luogu.com.cn/problem/P1019
代码
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 22*2;
string s[maxn];
bool vis[maxn];
char f;
int n;
int ans = -INF;
int judge(string str1, string str2){
int len = min(str1.length(), str2.length());
for(int i=1;i<=len;i++){
if(str1.substr(str1.length()-i, i) == str2.substr(0, i)){
if(i == len || i == 0)return 0;
else return i;
}
}
return 0;
}
void dfs(string cur, int tot){
if(tot == n){
ans = max(ans, int(cur.length()));
return;
}
ans = max(ans, int(cur.length()));
for(int i=0;i<n;i++){
if(!vis[i]){
if(tot == 0){
if(f == s[i][0]){
vis[i] = 1;
dfs(cur + s[i], tot + 1);
vis[i] = 0;
}
}
else{
int len = judge(cur, s[i]);
if(len>0){
vis[i] = 1;
dfs(cur + s[i].substr(len, s[i].length() - len), tot + 1);
vis[i] = 0;
}
}
}
}
}
int main(){
scanf("%d", &n);
int k = n;
for(int i=0;i<n;i++){
cin>>s[i];
s[k++] = s[i];
}
n = n*2;
cin>>f;
dfs("", 0);
cout<<ans<<endl;
return 0;
}
DFS与路径问题
这类问题和与解的个数问题非常相似,另起一个标题是因为想多点字数 。DFS搜索过程就是寻找一条一条的路径。这类问题有挺多的,这里我只接触到染色问题,以后遇到还会修改。
染色问题就是寻找连通块的问题,这类题不同题目变化挺多的,重点是连通性。需找几个连通块,甚至添加一些元素使的区域连通,观察有几种不同的连通块等等
这里挂一个模板题
https://blog.csdn.net/professor_Xie/article/details/112959398
DFS用法也是千变万化,以后遇到了有意思的题目再更新
广度优先搜索
广度优先搜索一般与队列(或优先队列)结合使用,每一步生成的所有满足条件的解都用队列保存起来,然后一一取出搜索直到找到解或者队列为空。
BFS的代码都差不过,不同题目代码也相差不大。
BFS与图
BFS在图上应用特别多,比如能否到达某个点,到达某个点的最快时间等等;这些是BFS最常见的用法。这里说一个BFS与时间的问题,有的题目每个点的可达状态是动态变化的,这里就要求出最早的不可达状态
挂一个模板题
https://blog.csdn.net/professor_Xie/article/details/112894897
BFS与状态可达问题
BFS搜索的一般比DFS快,所以在某些状态是否可达的问题上应用比DFS广。
挂一个BFS与字符串的题
https://www.luogu.com.cn/problem/P1032
代码
#include<iostream>
#include<string>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<map>
using namespace std;
struct node{
string str;
int step;
friend bool operator<(node a,node b){
return a.step > b.step;
}
};
map<string,bool>mp;
string st,en;
int len;
string s1[10];
string s2[10];
priority_queue<node>Q;
int bfs(){
node e1, e2;
mp[st] = 1;
e1.str = st;e1.step = 0;
Q.push(e1);
while(!Q.empty()){
e1 = Q.top();
Q.pop();
if(e1.step > 10)continue;
if(e1.str == en)return e1.step;
int L = e1.str.length();
for(int i=0;i<L;i++){
for(int j=0;j<len;j++){
e2 = e1;
if(!e1.str.compare(i,s1[j].length(),s1[j])){
e2.str.replace(i,s1[j].length(),s2[j]);
e2.step++;
if(mp[e2.str])continue;
if(e2.step<=10){
Q.push(e2);
}
mp[e2.str] = 1;
}
}
}
}
return -1;
}
int main(){
cin>>st>>en;
string str1, str2;
while(cin>>str1>>str2){
s1[len] = str1;
s2[len++] = str2;
}
int ans = bfs();
if(ans == -1){
printf("NO ANSWER!\n");
}
else printf("%d\n",ans);
return 0;
}
作者水平有限,多多包涵