深度优先搜索(dfs)暴力偏入门向(1)

几道比较不错的深搜练习题(迷宫、红与黑、马走日、单词接龙,纯暴力无优化无剪枝)

写出深搜很重要的两点:1递归搜索树 2明确当前的状态
在这里插入图片描述来源:acwing

//剖析一下自己写的深搜代码
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 110;

int k, n;
int a, b, c, d;
char g[N][N];
int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
bool st[N][N];

bool dfs(int x, int y){                         //我用的是带返回值的dfs函数,也可以用一个不带返回值的,但是需要用变量标记一下
    if(x == c && y == d)    return true;        //终止条件
    st[x][y] = true;
    for(int i = 0;i < 4;i++){
        int tx = x + dx[i], ty = y + dy[i];
        if(tx < 1 || tx > n || ty < 1 || ty > n)    continue;
        if(st[tx][ty] || g[tx][ty] == '#')    continue;
        if(dfs(tx, ty))    return true;         //从终止条件那里一直迭代回到根节点
    }
    return false;                               //这个false只有在第一层才会有效果
}

int main(){
    cin >> k;
    while(k--){
        memset(st, false, sizeof st);
        cin >> n;
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= n;j++)
                cin >> g[i][j];
        cin >> a >> b >> c >> d;
        a ++ , b ++ , c ++ , d ++;              //注意下标起始位置,习惯从1开始的要注意这道题给的起点
        if(g[a][b] == '#'){                     //小坑:起点处就是障碍物那么肯定到不了
            cout << "NO" << endl;
            continue;
        }
        cout << (dfs(a, b) ? "YES" : "NO") << endl;
    }
    return 0;
}

在这里插入图片描述
来源:acwing

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 25;

int n, m;
char g[N][N];
bool st[N][N];
int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};

int dfs(int x, int y){                                       //应用带返回值的dfs
    st[x][y] = true;                                         //连通性问题无需回溯
    int sum = 1;                                             //当前这个结点默认有1个
    for(int i = 0;i < 4;i++){
        int tx = x + dx[i], ty = y + dy[i];
        if(tx < 1 || tx > n || ty < 1 || ty > m)    continue;
        if(st[tx][ty] || g[tx][ty] == '#')    continue;
        sum += dfs(tx, ty);                                  //把从这个点遍历的加回来,相当于动态规划的感觉
    }                                                        //第一层返回的就是我们要的结点数
    return sum;
}

int main(){
    while(cin >> m >> n, n | m){
        memset(st, false, sizeof st);
        int x, y;
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= m;j++){
                cin >> g[i][j];
                if(g[i][j] == '@')    x = i, y = j;
            }
        cout << dfs(x, y) << endl;    
    }
    return 0;
}

在这里插入图片描述
来源acwing

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 13;

int t;
int n, m, x, y;
bool st[N][N];
int dx[] = {1, 2, 2, 1, -1, -2, -2, -1}, dy[] = {-2, -1, 1, 2, 2, 1, -1, -2};

int dfs(int x, int y, int s){                     //加个参数方便判断是否走全
    if(s == n * m)    return 1;
    int ans = 0;                                  //记录一下
    st[x][y] = true;
    for(int i = 0;i < 8;i++){
        int tx = x + dx[i], ty = y + dy[i];
        if(tx < 1 || tx > n || ty < 1 || ty > m)    continue;
        if(st[tx][ty])    continue;
        ans += dfs(tx, ty, s + 1);
    }
    st[x][y] = false;                             //需要回溯
    return ans;
}

int main(){
    cin >> t;
    while(t--){
        memset(st, false, sizeof st);
        cin >> n >> m >> x >> y;
        x ++ , y ++;
        cout << dfs(x, y, 1) << endl;
    }
    return 0;
}

在这里插入图片描述
来源:acwing

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <unordered_map>

using namespace std;

const int N = 30;

int n, d, length, ans;
char c;
string str[N];
unordered_map<string, int> m;

int is_fixed(string s, string t){      //算最少重合数
    int res = 0;
    for(int i = 1;i < min((int)s.size(), (int)t.size());i++){
        res = i;
        for(int j = 0;j < i;j++)
            if(s[s.size() - i + j] != t[j]){
                res = 0;
                break;
            }
        if(!res)    continue;
        else    return res;
    }
    return res;
}

int dfs(string s){
    ans = max(ans, (int)s.size());
    string q = s;
    for(int i = 0;i < n;i++){
        if(m[str[i]] && (d = is_fixed(s, str[i]))){
            s += str[i].substr(d, str[i].size() - d);
            m[str[i]]--;
            dfs(s);
            s = q;
            m[str[i]]++;                                      //回溯
        }
    }
    return ans;
}

int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);     //加速
    cin >> n;
    for(int i = 0;i < n;i++){    
        cin >> str[i];
        m[str[i]] = 2;
    }
    cin >> c;
    for(int i = 0;i < n;i++)
        if(str[i][0] == c){
            ans = 0;
            m[str[i]]--;
            length = max(length, dfs(str[i]));
        }
    cout << length << endl;
    
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值