2024.1.25学习笔记(dfs)

近期着手参加2024年蓝桥杯A组省赛,跟随罗勇军老师的20周备赛博客进行学习,对博客中的题目进行学习、整理、编写此博客,目的为与大家广泛交流!

罗永军老师20周蓝桥杯训练计划icon-default.png?t=N7T8https://blog.csdn.net/weixin_43914593/article/details/133951894

目录

1 全排列问题

  1. 题目链接

    全排列问题 - 洛谷 https://www.luogu.com.cn/problem/P1706

  2. 代码

    #include<bits/stdc++.h>
    using namespace std;
    ​
    int n;
    int a[10];
    int b[10];
    int vis[10];
    ​
    void dfs(int step){
      if(step == n + 1){
        for(int i = 1;i <= n;i++){
          printf("%5d",b[i]);//场宽一会看一下啥意思  
        }
        cout<<endl;
        return;
      }
      for(int i = 1;i <= n;i++){
        if(vis[i] == 0){
          b[step] = a[i];
          vis[i] = 1;//标记
          dfs(step + 1);
          vis[i] = 0;//回溯
        }
      }
      return;
    }
    int main(){
      cin>>n;
      for(int i = 1;i <= n;i++) a[i] = i;
      
      dfs(1);
    
    
      return 0;
    }
  3. 题解
    step代表此次DFS正在放入第step个数字。我们要求n个数字全排列,当step达到n + 1时,我们这一排列完成。 vis[]对数字进行标记,vis[i] = 1,代表该排列中存在i;vis[i] = 0,代表该排列不存在i。对于存在的我们不再放入,不存在的可以放入。 第step个数字可以已经放入数字后,我们可以对第step个数字放入新的数字,调用DFS(step + 1),调用后进行回溯,此数字不再被放入排列中。

2 最大连通

  1. 题目链接

    用户登录

  2. 代码

    //最大连通
    #include<bits/stdc++.h>
    using namespace std;
    ​
    char a[40][70];//30行,60列
    //dx,dy可以合并出4个方向
    int dx[4] = {-1,0,1,0};
    int dy[4] = {0,1,0,-1};
    long long ans;
    ​
    long long dfs(int x,int y){
      cerr<<x<<" "<<y<<endl;
      if(a[x][y] == '0') return 0;
      int ans = 1;
      a[x][y] = '0';
      for(int i = 0;i < 4;i++){
        int nx = x + dx[i],ny = y + dy[i];
        if(nx < 0 || ny < 0 || nx >= 30 || ny >= 60) continue;
        ans += dfs(nx,ny);
      }
      return ans;
    }
    ​
    int main(){
      for(int i = 0;i < 30;i++){
        cin>>a[i];
      }
      
      for(int i = 0;i < 30;i++){
        for(int j = 0;j < 60;j++){
          if(a[i][j] == '1'){
            ans = max(ans,dfs(i,j));
          }
        }
      }
      
      cout<<ans<<endl;
      return 0;
    }
  3. 题解

    地图长、宽固定:30行、60列。我们用char[][]接收。遍历每一位置,对没有搜索过且可连通的位置进行dfs搜索。 dfs搜索中,我们传入当前的x、y,将当前位置标记为0(代表我们已经搜索过),ans定为1。我们判定其四个方位是否可以继续连通,对可连通的位置继续调用dfs,判定其周边的四个方位是否连通。dfs在遇到当前位置为0(本就不连通或搜索过时),会返回0,同时不在继续调用dfs。 对ans进行累计,一层层递归进入,返回最终的ans值。

3 全球变暖

  1. 题目链接

    用户登录

  2. 代码

    #include<bits/stdc++.h>
    using namespace std;
    ​
    const int N = 1e3 + 10;
    ​
    int n;
    char mp[N][N];
    long long ans;
    int d[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
    int vis[N][N];
    bool flag;
    ​
    void dfs(int x,int y){
      vis[x][y] = 1;//被搜过
      if(mp[x + 1][y] == '#' && mp[x - 1][y] == '#'
      && mp[x][y + 1] == '#' && mp[x][y - 1] == '#'){
        //cerr<<x<<" "<<y<<endl;
        flag = true;//有高地
      }
      for(int i = 0;i < 4;i++){
        int nx = x + d[i][0],ny = y + d[i][1];
        if(vis[nx][ny] == 0 && mp[nx][ny] == '#'){
          dfs(nx,ny);
        }
      }
    }
    ​
    int main(){
      cin>>n;
      for(int i = 0;i < n;i++){
        cin>>mp[i];
      }
      
      for(int i = 0;i < n;i++){
        for(int j = 0;j < n;j++){
          if(mp[i][j] == '#' && vis[i][j] == 0){
            flag = false;//回溯flag
            dfs(i,j);
            if(!flag) ans++;
          }
        }
      }
      cout<<ans<<endl;
      
      
      return 0;
    }
  3. 题解

    在最大连通的基础上,多了一个判定问题,即当前岛屿是否会沉没。我们统计最终沉没岛屿数量; 解决方案,使用flag,对于不能沉默的岛屿,我们定flag = true;可以沉没的岛屿,我们定flag = false; 判定岛屿是否沉没的方法:判上下左右是否为'#',若连通块中的某个点满足此条件,则该岛屿不会沉没。

4 N皇后

  1. 题目链接

    P1158 - 八皇后 - New Online Judge http://oj.ecustacm.cn/problem.php?id=1158

  2. 代码

    #include<bits/stdc++.h>
    using namespace std;
    
    int tot;//记录方案数
    int n;
    int ans[30];//第x行皇后放在第几列
    int vis[30];//第y列放了皇后
    int vis1[30];//主对角线放了皇后
    int vis2[30];//副对角线放了皇后
    
    void dfs(int x){
      if(x == n + 1){
        tot++;
        if(tot <= 3){
          for(int i = 1;i <= n;i++){
            cout<<ans[i]<<" ";
          }
          cout<<endl;
        }
        return;  
      }
      
      for(int y = 1;y <= n;y++){
        if(vis[y]) continue;
        if(vis1[x + y]) continue;
        if(vis2[x - y + n]) continue;
        ans[x] = y;
        vis[y] = 1;vis1[x + y] = 1;vis2[x - y + n] = 1;
        dfs(x + 1);
        vis[y] = 0;vis1[x + y] = 0;vis2[x - y + n] = 0;
      }
      
    }
    
    
    int main(){
      cin>>n;
      dfs(1);  
      cout<<tot<<endl;
      
      
      return 0;
    }
  3. 题解

    本题属于dfs中排列组合 规律:主对角线vis1,x + y不变;副对角线vis2,x - y不变,我们实际使用时为保证数组下标 > 0,x - y + n不变;除此之外,只需判定该列是否存在皇后vis[]; 对于该列、主对角线、副对角线存在皇后的,我们不再放入;对于可以放入的,我们放入并标记。该排列组合完成后,需要进行回溯。退出条件为 n + 1,与排列组合一致,我们只需放入n个。

  • 22
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值