搜索总结 (更新中)

介绍

搜索可以说是万能解题方法,在解空间中搜索满足条件的解。分为深度优先搜索(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;

}

作者水平有限,多多包涵

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值