acwing算法提高之搜索--DFS连通性模型和搜索顺序

123 篇文章 1 订阅

1 专题说明

本专题用来记录使用DFS连通性模型或DFS搜索顺序求解的题目。

2 训练

题目11112迷宫

考点:dfs

C++代码如下,

#include <iostream>
#include <cstring>

using namespace std;

//宏定义
#define x first
#define y second

const int N = 110;
int n;
char g[N][N];
bool st[N][N];
pair<int,int> start_node, end_node;
int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

void dfs(int x, int y) {
    st[x][y] = true;
    
    //(x,y)可以走到哪里
    for (int k = 0; k < 4; ++k) {
        int nx = x + dirs[k][0];
        int ny = y + dirs[k][1];
        
        if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
        if (st[nx][ny]) continue;
        if (g[nx][ny] == '#') continue;
        
        dfs(nx, ny);
    }
    return;
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        cin >> n;
        for (int i = 0; i < n; ++i) cin >> g[i];
        cin >> start_node.x >> start_node.y >> end_node.x >> end_node.y;
        memset(st, 0, sizeof st); //每次都要进行重置
        if (g[start_node.x][start_node.y] == '.' && g[end_node.x][end_node.y] == '.') {
            dfs(start_node.x, start_node.y);
        }
        if (st[end_node.x][end_node.y]) {
            cout << "YES" << endl;
        } else {
            cout << "NO" << endl;
        }
    }
    
    return 0;
}

题目21113红与黑

C++代码如下,

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

using namespace std;

const int N = 30;
int n, m;
char g[N][N];
bool st[N][N];
int res = 0;
int dirs[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};

void dfs(int i, int j) {
    
    for (int k = 0; k < 4; ++k) {
        int x = i + dirs[k][0];
        int y = j + dirs[k][1];
        
        if (x < 1 || x > n || y < 1 || y > m) continue;
        if (g[x][y] != '.') continue;
        if (st[x][y]) continue;
        
        st[x][y] = true;
        res += 1;
        dfs(x, y); //调用时判断,是否走过了
    }    
    
    return;
}

int main() {
    while (cin >> m >> n) {
        if (m == 0 && n == 0) break;
        
        memset(g, 0, sizeof g);
        memset(st, 0, sizeof st);
        res = 0;
        for (int i = 1; i <= n; ++i) {
            cin >> g[i] + 1;
        }
        
        pair<int, int> node_start;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (g[i][j] == '@') {
                    node_start = make_pair(i, j);
                }
            }
        }
        
        res += 1;
        dfs(node_start.first, node_start.second);
        cout << res << endl;
    }
    
    return 0;
}

题目31116马走日

C++代码如下,

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

using namespace std;

const int N = 15;
int n, m;
bool visited[N][N];
int res = 0;

int dirs[8][2] = {{1,2}, {2,1}, {-1,2}, {-2,1}, {-1,-2}, {-2,-1}, {1,-2}, {2,-1}};

bool check() {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (visited[i][j] == false) {
                return false;
            }
        }
    }
    return true;
}

void dfs(int i, int j) {
    if (check()) {
        res += 1;
        return;
    }
    
    for (int k = 0; k < 8; ++k) {
        int x = i + dirs[k][0];
        int y = j + dirs[k][1];
        
        if (x < 0 || x >= n || y < 0 || y >= m) continue;
        if (visited[x][y]) continue;
    
        visited[x][y] = true;
        dfs(x, y);
        visited[x][y] = false;
    }
    return;
}

int main() {
    int T;
    cin >> T;
    
    while (T--) {
        int i, j;
        cin >> n >> m >> i >> j;
        
        //重置visited数组
        memset(visited, 0, sizeof visited);
        res = 0;
        
        visited[i][j] = true;
        dfs(i, j);
        cout << res << endl;
    }
    
    return 0;
}

题目41117单词接龙

C++代码如下,

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

using namespace std;

int n;
vector<string> words;
vector<int> cnt;
string start_s;
int res = 1;

void dfs(string s) {
    
    res = max(res, (int)s.size() - 1);
    
    for (int j = s.size() - 1; j >= 1; --j) {
        string t = s.substr(j);
        
        //有多少word能接在t后面
        for (int i = 0; i < words.size(); ++i) {
            int idx = words[i].find(t);
            if (idx == 0) {
                //重合部分的长度为s.size() - j
                if (t.size() == words[i].size()) continue; //跳过,检查下一个word
                if (cnt[i] == 2) continue; //第i个单词已经用了2次了
                
                int length = s.size();
                s = s + words[i].substr(t.size());
                cnt[i] += 1;
                
                dfs(s);
                
                cnt[i] -= 1;
                s = s.substr(0, length);
                
            }
        }
    }
    return;
}


int main() {
    cin >> n;
    words.resize(n);
    cnt.resize(n, 0); //每个单词至多被使用2次
    for (int i = 0; i < n; ++i) cin >> words[i];
    cin >> start_s;
    
    string s = "_" + start_s;
    dfs(s);
    
    cout << res << endl;
    
    return 0;
}

题目51118分成互质组

C++代码如下,

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

using namespace std;

int n;
vector<int> nums(15);
vector<vector<int>> group(15);
int groupsize = 0;
int res = 10;

int gcd(int x, int y) {
    return y ? gcd(y, x % y) : x;
}

void dfs(int i, int groupsize) {
    if (i == n) {
        res = min(res, groupsize);
        return;
    }
    
    int x = nums[i];

    for (int j = 0; j < groupsize; ++j) {
        //x能否放入第j组中
        vector<int> a = group[j];
        
        bool flag = true;
        for (auto y : group[j]) {
            if (gcd(x, y) != 1) {
                flag = false;
                break;
            }
        }
        if (flag) {
            group[j].emplace_back(x);
            dfs(i + 1, groupsize);
            group[j].pop_back();
        }
    }
    
    group[groupsize].emplace_back(x);
    dfs(i + 1, groupsize + 1);
    group[groupsize].pop_back();
    
    return;
}

int main() {
    cin >> n;
    for (int i = 0; i < n; ++i) cin >> nums[i];
    
    dfs(0, 0);
    cout << res << endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YMWM_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值