DFS

description: DFS 全称是 Depth First Search,中文名是深度优先搜索,是一种用于遍历或搜索树或图的算法。所谓深度优先,就是说每次都尝试向更深的节点走。

该算法讲解时常常与 BFS 并列,但两者除了都能遍历图的连通块以外,用途完全不同,很少有能混用两种算法的情况。

DFS 常常用来指代用递归函数实现的搜索,但实际上两者并不一样。有关该类搜索思想请参阅 DFS(搜索).

DFS 最显著的特征在于其 递归调用自身。同时与 BFS 类似,DFS 会对其访问过的点打上访问标记,在遍历图时跳过已打过标记的点,以确保 每个点仅访问一次。符合以上两条规则的函数,便是广义上的 DFS。

843. n-皇后问题

代码:

#include <iostream>

using namespace std;

const int N = 20;

int n;
char g[N][N];
bool col[N], dg[N], udg[N];

void dfs(int u)
{
    if (u == n)
    {
        for (int i = 0; i < n; i ++ ) puts(g[i]);
        puts("");
        return;
    }

    for (int i = 0; i < n; i ++ )
        if (!col[i] && !dg[u + i] && !udg[n - u + i])
        {
            g[u][i] = 'Q';
            col[i] = dg[u + i] = udg[n - u + i] = true;
            dfs(u + 1);
            col[i] = dg[u + i] = udg[n - u + i] = false;
            g[u][i] = '.';
        }
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            g[i][j] = '.';

    dfs(0);

    return 0;
}sfddfff

枚举

3503. 数组划分

一个数组中有若干正整数,将此数组划分为两个子数组,使得两个子数组的各元素之和 a,b 的差最小。

输入格式

共一行,包含若干个正整数,表示给定数组。

输出格式

以降序的顺序,输出两个子数组的各元素之和。

数据范围

给定数组的元素个数范围 [2,1000]。
给定数组的元素取值范围 [1,1000000]。

输入样例:

10 20 30 10 10

输出样例:

40 40

思路:

暴搜,dfs枚举每个数:选或是不选:

若是当前总和小于总和的一般,则可以选当前数,也可以不选当前数

否则一定不选当前数。

注意,dfs枚举一定要有剪枝

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

using namespace std;

const int N = 1010;
int n = 0;
int a[N];
int s, s1;
bool flag = false;

void dfs(int u, int now_sum){
    if(flag)return;
    if(u == n)return;
    if(now_sum <= s / 2){
        s1 = max(s1, now_sum);
        
        //dfs一定要有剪枝操作,否则最后一个样例过不了
        //最后一个样例大概是:有一个特别大的数,其他数加起来都没他大
        //所以当我们遍历到这样的数a[u],答案一定是[a[u], s - a[u]]
        if(s1 == s / 2)return;
        else if(a[u] > s / 2){
            s1 = s - a[u];
            flag = true;
        }
        
        //选当前的数
        dfs(u + 1, now_sum + a[u]);
    }
    dfs(u + 1, now_sum);
}

int main()
{
    while(cin >> a[n], a[n])s += a[n ++];
    dfs(0, 0);
    cout << s - s1 << " " << s1;
    return 0;
}

1116. 马走日

题目:

马在中国象棋以日字形规则移动。

请编写一段程序,给定 n∗m 大小的棋盘,以及马的初始位置 (x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

思路:

每次走的总步数达到n*m的时候,ans++

代码:

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

using namespace std;

const int N = 10;

int n, m;
bool st[N][N];
int ans;
int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};

void dfs(int x, int y, int cnt)
{
    if (cnt == n * m)
    {
        ans ++ ;
        return;
    }
    st[x][y] = true;

    for (int i = 0; i < 8; i ++ )
    {
        int a = x + dx[i], b = y + dy[i];
        if (a < 0 || a >= n || b < 0 || b >= m) continue;
        if (st[a][b]) continue;
        dfs(a, b, cnt + 1);
    }

    st[x][y] = false;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        int x, y;
        scanf("%d%d%d%d", &n, &m, &x, &y);

        memset(st, 0, sizeof st);
        ans = 0;
        dfs(x, y, 1);

        printf("%d\n", ans);
    }

    return 0;
}

1117. 单词接龙

题目:

单词接龙是一个与我们经常玩的成语接龙相类似的游戏。

现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”,每个单词最多被使用两次。

在两个单词相连时,其重合部分合为一部分,例如 beast 和 astonish ,如果接成一条龙则变为 beastonish。

我们可以任意选择重合部分的长度,但其长度必须大于等于1,且严格小于两个串的长度,例如 at 和 atide 间不能相连。

思路:

代码:

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

using namespace std;

const int N = 21;

int n;
string word[N];
int g[N][N];
int used[N];
int ans;

void dfs(string dragon, int last)
{
    ans = max((int)dragon.size(), ans);
    used[last] ++ ;
    for (int i = 0; i < n; i ++ )
        if (g[last][i] && used[i] < 2)
            dfs(dragon + word[i].substr(g[last][i]), i);

    used[last] -- ;
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> word[i];
    char start;
    cin >> start;

    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
        {
            string a = word[i], b = word[j];
            for (int k = 1; k < min(a.size(), b.size()); k ++ )
                if (a.substr(a.size() - k, k) == b.substr(0, k))
                {
                    g[i][j] = k;
                    break;
                }
        }

    for (int i = 0; i < n; i ++ )
        if (word[i][0] == start)
            dfs(word[i], i);

    cout << ans << endl;

    return 0;
}

1118. 分成互质组

题目:

给定 n 个正整数,将它们分组,使得每组中任意两个数互质。

至少要分成多少个组?

思路:

代码:

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
const int N = 10;
int gcd(int x, int y) {
    return y ? gcd(y, x % y) : x;
}
int n, a[N], ans = N, len;
vector<int> g[N];
bool inline check(int u, int c) {
    for (int i = 0; i < g[c].size(); i++)
        if(gcd(g[c][i], u) > 1) return false;
    return true;

void dfs(int u) {
    if(u == n) {
        ans = min(ans, len);
        return;
    }
    for(int i = 0; i < len; i++) {
        if(check(a[u], i)) {
            g[i].push_back(a[u]);
            dfs(u + 1);
            g[i].pop_back();
        }
    }
    g[len++].push_back(a[u]);
    dfs(u + 1);
    g[--len].pop_back();
}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) scanf("%d", a + i);
    dfs(0);
    printf("%d\n", ans);
}

生成全排列

#include <bits/stdc++.h>

using namespace std;

const int N = 15;

vector<vector<int>> res;
int n;
int a[N];
bool st[N];

void dfs(int u){
    if(u == n){    
        vector<int> line;
        for(int i = 0; i < n; i ++){
            line.push_back(a[i]);
        }
        res.push_back(line);
    }
    for(int i = 0; i < n;i ++){
        if(st[i] == false){
            a[u] = i;
            st[i] = true;
            dfs(u + 1);
            st[i] = false;
        }
    }
}


int main(){
    cin >> n;
    for(int i = 0; i < n; i++){
        cin >> a[i];
    }
    dfs(0);
    for(int i = 0; i < res.size(); i ++){
        for(int j = 0;j < res[i].size(); j ++){
            cout << res[i][j] << " " ;   
        }
        cout << endl;
    }
    return 0;
}

有重复数字的全排列

class Solution {
    public:
    
    vector<vector<int>> res;
    vector<int> path;

    vector<vector<int>> permutation(vector<int>& nums) {
        path.resize(nums.size());
        sort(nums.begin(),nums.end());
        dfs(nums,0,0,0);
        return res;
    }

    void dfs(vector<int> &nums,int u,int start, int state){
        if(u == nums.size()){
            res.push_back(path);
            return;
        }

        if (!u || nums[u] != nums[u - 1]) start = 0;

        for(int i = start;i < nums.size(); i ++){
            if(!(state >> i & 1)){
                path[i] = nums[u];
                dfs(nums,u+1,i+1,state + (1 << i));
            }
        }
    }

};

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1149440709@qq.com

×

喜欢就点赞,疼爱就打赏