深度搜索基础题目列表

深度优先搜索的判断是否已经被标记的数组的判断写在循环里面和循环外面都是可以的

迷宫:

https://www.jisuanke.com/problem/T1595

  • 代码:
#include<bits/stdc++.h>
using namespace std;
int n,m;
char s[11][11];
int wz[4][2] = {{-1,0}, {0,-1}, {1,0}, {0,1}};
bool gr[11][11];
bool in(int tx, int ty) {
    return tx < n && ty < m && tx >= 0 && ty >= 0;
}
bool f;
void dfs(int x, int y) {
    if(f == true) {
        return;
    }
    if(s[x][y] == 'T') {
        f = true;
        return;
    }
    gr[x][y] = true;
    for(int i = 0; i < 4; i++) {
        int tx = x + wz[i][0];
        int ty = y + wz[i][1];
        if(in(tx, ty) && !gr[tx][ty] && s[tx][ty] != '*') {
            dfs(tx,ty);
        }
    }
    gr[x][y] = false;
}
int main() {
    cin >> n >> m;
    int startx, starty;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            cin >> s[i][j];
            if(s[i][j] == 'S') {
                startx = i;
                starty = j;
            }
        }
    }
    dfs(startx, starty);
    if(f){
        cout << "yes";
    }else {
        cout << "no";
    }
    return 0;
}

马走日:

https://www.jisuanke.com/problem/T1217

  • 代码
#include<iostream>
#include<string.h>
using namespace std;
int n, m;
int T;
int sx, sy;
int dir[8][2] = {{-1, 2}, {-1, -2}, {-2, -1}, {-2, 1}, {1, 2}, {1, -2}, {2, -1}, {2, 1}};
bool gr[22][22];

int ans;
//有一个疑惑的地方,每次进到循环内部都需要检测是否都走过l
bool isfull() {
    bool isf = true;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            isf = isf & gr[i][j];
        }
    }
    return isf;
}
bool in (int tx, int ty) {
    return 0 <= tx && tx < n && ty >= 0 && ty < m;
}

void dfs(int x, int y) {

    
    if(isfull()) {
        ans++;
        return;
    }

    for(int i = 0; i < 8; i++) {
        int tx = x + dir[i][0];
        int ty = y + dir[i][1];
        if(in(tx, ty) && !gr[tx][ty]) {
            gr[tx][ty] = true;
            dfs(tx, ty);
            gr[tx][ty] = false;
        }
    }
    
}

int main() {
    cin >> T;
    for(int i = 0; i < T; i++) {
        cin >> n >> m >> sx >> sy;
        ans = 0;
        memset(gr,0,sizeof(gr));
        gr[sx][sy] = true;
        dfs(sx, sy);
        //出现了错误,这里没有换行
        cout << ans << endl;
    }
    
    
    return 0;
}

组合总和

https://leetcode.cn/problems/combination-sum/description/

  • 代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void dfs(vector<int>& nums, int index, int sum) {
        if(sum == 0) {
            result.push_back(path);
            return;
        }
        if(sum < 0) {
            return;
        }
        for(int i = index; i < nums.size(); i++) {
            path.push_back(nums[i]);
            dfs(nums, i, sum - nums[i]);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        dfs(candidates, 0, target);
        return result;
    }
};

组合总和Ⅱ

https://leetcode.cn/problems/combination-sum-ii/description/

  • 代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void dfs(vector<int>& nums, int index, int sum, vector<bool>& used) {
        if(sum == 0) {
            result.push_back(path);
            return;
        }
        if(sum < 0) {
            return;
        }
        for(int i = index; i < nums.size(); i++) {
            //树层去重
            if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                //满足条件说明:跳过了前面的一个一样的数直接选了后面的数,不能这样,直接跳过
                continue;
            }
            sum -= nums[i];
            path.push_back(nums[i]);
            used[i] = true;
            dfs(nums, i + 1, sum, used);
            used[i] = false;
            path.pop_back();
            sum += nums[i];
        }

    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        vector<bool> used(candidates.size(), 0);
        dfs(candidates, 0, target, used);
        return result;
    }
};

全排列

https://leetcode.cn/problems/permutations/

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums, vector<bool>& used) {
        // 此时说明找到了一组
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            if(used[i] == true) {
                continue;
            }
            used[i] = true;
            path.push_back(nums[i]);
            backtracking(nums, used);
            path.pop_back();
            used[i] = false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};

全排列Ⅱ

https://leetcode.cn/problems/permutations-ii/description/

  • 代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void dfs(vector<int>& nums, vector<bool>& used) {
        if(path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++) {
            // 1 1 2
            //前面取了1之后,后面不能取得1
            if((i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) || used[i] == true) {
                continue;
            }
            path.push_back(nums[i]);
            used[i] = true;
            dfs(nums, used);
            used[i] = false;
            path.pop_back();
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<bool> used(nums.size(), 0);
        sort(nums.begin(), nums.end());
        dfs(nums, used);
        return result;
    }
};

我们对比'组合总和Ⅱ'和 '全排列Ⅱ'可以看出三个问题:

  • 首先是组合和排列的问题,区别是在于index的设置:
    • 组合是有index设置的,也就是树枝上不去回头取。
    • 排列是不用设置index的,因为可以回头取。
    • 如果本身还能重复取的话,那么在回溯的时候dfs的参数里不是i + 1,而是i,因为本身可以取。
  • 树枝和树层的去重,在于used数组:
    • 无重复数据的:就是正常的used使用。
    • 有重复数据的:used的true和false分别要进行树枝的和树层的去重(记得数组要排序)。
  • 排列的回头取的时候还需要判断该数字是不是用过,因为可以回头取(就像是'全排列'的条件中有|| used[i] == true)。

N皇后

https://leetcode.cn/problems/n-queens/description/

  • 代码
class Solution {
public:
    vector<string> path;
    vector<vector<string>> result;

    
    //这个检查的过程可以用数组来简化,没必要循环判断,所以这里也算是一种改进
    bool check(int n, int x, int y, vector<bool>& ys, vector<bool>& d_45, vector<bool>& d_135) {
        return !ys[y] && !d_45[x + y] && !d_135[y - x + n - 1];
    }
    //按照每一行来回溯
    void dfs(int n, int x, vector<bool>& ys, vector<bool>& d_45, vector<bool>& d_135) {
        if(x == n) {
            result.push_back(path);
            return;
        }
        for(int y = 0; y < n; y++) {
            if(check(n, x, y, ys, d_45, d_135)) {
                path[x][y] = 'Q';
                ys[y] = true;
                d_45[x + y] = true;
                d_135[y - x + n - 1] = true;

                dfs(n, x + 1, ys, d_45, d_135);
                
                d_135[y - x + n - 1] = false;
                d_45[x + y] = false;
                ys[y] = false;
                path[x][y] = '.';
            }
        }
    }
    vector<vector<string>> solveNQueens(int n) {
       
        //分别用来判断同一列,45°对角线和135°对角线有没有皇后
        vector<bool> ys(2*n, false);
        vector<bool> d_45(2*n + 1, false);
        vector<bool> d_135(2*n + 1, false);

        path = vector<string>(n, string(n, '.'));
        dfs(n, 0, ys, d_45, d_135);
        return result;
    }
};

N皇后的判断的改进也算是一种优化,比原始的判断条件快了很多:

  • 同一列的判断,很简单,用一个数组表示即可,数组的下标也是相对应的
  • 45°的判断:用数组d_45来表示,下标是处于0到x + y之间,规律是x+y相同
  • 135°的判断:用数组d_135来表示,下标处于0到-x - y到x + y之间,规律是y - x相同

作物杂交

https://i.cnblogs.com/articles/edit;postId=17753438

  • 解释:
    有时候dfs的状态量会有很多,但是要做好规划分类,思路清晰才能做好,看好每一步的关键是什么
  • 代码
    #include<iostream>
    #include<vector>
    #include<string.h>
    using namespace std;
    typedef pair<int, int> pei;
    const int MAXN = 2001;
    
    
    int zwcst[MAXN];//记录作物成熟的时间
    
    int havezw[MAXN];//记录当前作物库当中有没有该作物
    
    int mint[MAXN];//记录当前作物库当中有的作物的最小生成时间
    
    vector<pei> zwfa[MAXN];
    
    int n, m, k, target;
    
    void dfs(int i) {
        if(havezw[i]) {
            return;
        }
    
        for(auto& it : zwfa[i]) {
            int A = it.first, B = it.second;
            if(!havezw[A]) {
                dfs(A);
            }
            if(!havezw[B]) {
                dfs(B);
            }
            mint[i] = min<int>(mint[i], max<int>(zwcst[A], zwcst[B]) + max<int>(mint[A], mint[B]));
        }
        havezw[i] = true;
    }
    
    int main() {
        //初始化
        memset(mint, 0x3f3f, sizeof(mint));
    
        cin >> n >> m >> k >> target;
    
        for(int i = 1; i <= n; i++) {
            cin >> zwcst[i];
        }
        int a;
        for(int i = 1; i <= m; i++) {
            cin >> a;
            havezw[a] = true;
            mint[a] = 0;
        }
        int b, c;
        for(int i = 0; i < k; i++) {
            cin >> a >> b >> c;
            zwfa[c].push_back(pei(a, b));
        }
     
    
    
        dfs(target);//用于更新当前作物x的最小更新时间
        cout << mint[target];
        return 0;
    }
    
posted @ 2023-10-09 22:58  铜锣湾陈昊男  阅读(12)  评论(0)    收藏  举报