蓝桥杯DFS&BFS专题(入门)

蓝桥杯DFS&BFS专题

DFS

介绍

DFS是深度优先搜索算法,是一种用于图形搜索的算法。它的基本思想是:从初始状态出发,沿着最先发现的路径前进,直到最后可以到达目标状态为止

具体步骤如下:

  • 从初始状态出发,沿着第一条路径向前搜索;
  • 如果未到达终止状态,则继续沿着这条路径继续搜索;
  • 如果已经到达终止状态,则回溯,沿着另一条路径继续搜索;

img

伪代码

void dfs()//参数用来表示状态  
{  
    if(到达终点状态){  
        ...//根据题意添加  
        return;  
    }  ]
        
    //可能剪枝
    if(特殊状态)//剪枝
        return ;
    
    //重复过程
    for(扩展方式){  
        //满足什么条件才能重复继续的操作
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            //标记;  
            dfs(); 
            
            //回溯操作
            (还原标记);  
            //是否还原标记根据题意  
        }  
 
    }  
} 

例题

测试链接

排列数字

给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法,现在,请你按照字典序将所有的排列方法输出

输入格式
共一行,包含一个整数 n。

输出格式
按字典序输出所有排列方案,每个方案占一行。

数据范围 : 1 ≤ n ≤ 7

输入样例:

3

输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
AC代码
  • C/C++

    #include <iostream>
    using namespace std;
    const int N = 10;
    int n;
    int path[N];//保存数字组合
    bool st[N];//检测该数字有没有用过
    void dfs(int x){
    	if (x==n){
    		for (int i = 0; i < n; i++){
    			cout << path[i];
    		}
    		cout << endl;
    		return;
    	}
     
    	for (int i = 1; i <= n; i++){
    		if (!st[i]){
    			path[x] = i;
    			st[i] = true;
    			dfs(x + 1);
    			st[i] = false;
    		}
    	}
    }
    int main(){
    	cin >> n;
    	dfs(0);
    	return 0;
    }
    
  • JAVA

import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
    public static int n;
    public static int [] vis = new int[10];
    public static LinkedList<Integer> path = new LinkedList<>();
    public static Scanner sc = new Scanner(new BufferedInputStream(System.in));
    public static PrintStream ps = new PrintStream(System.out);
    public static void main(String[] args) {
        n = sc.nextInt();
        dfs(0);
    }

    private static void dfs(int x) {
        if (x == n){
            for (Integer item : path) {
                ps.print(item + " ");
            }
            ps.println();
            return ;
        }

        for (int i = 1; i <= n; i++) {
            if (vis[i] == 0){
                vis[i] = 1;
                path.add(i);
                dfs(x + 1);

                vis[i] = 0;
                path.removeLast();
            }
        }
    }
}
  • 技巧

    //其实就是一个全排列,可以调用对应函数或者API
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int path[10];
    int main(){
    	
    	int n ;
    	cin >> n;
    	for(int i = 1 ; i <= n ; i++) path[i] = i;
    	do{
    		for(int i = 1 ; i <= n ; i++){
    			cout << path[i];
    		}
    		cout << endl;
    	}while(next_permutation(path + 1,path + n + 1));
    	return 0;
    }
    
15级台阶

小蓝要上一个楼梯,共 15 级台阶。

小蓝每步可以上 1 级台阶,也可以上 2 级、3 级或 4 级,再多就没办法一步走到了。

每级台阶上有一个数值,可能正也可能负。每次走到一级台阶上,小蓝的得分就加上这级台阶上的数值。台阶上的数值依 次为: 1, 2, 1, 1, 1, 1, 5, 5, 4, -1, -1, -2, -3, -1, -9。

小蓝希望不超过 6 步走到台阶顶端,请问他得分的最大值是多少?

注意,小蓝开始站在地面上,地面没有分值。他最终要走到台阶顶端,所以最终一定会走到数值为 -9 的那级台阶,所以 -9

一定会加到得分里面。

AC代码

答案: 5

  • C++
#include<iostream>
#include<algorithm>
using namespace std;
int score[16] = {0,1,2,1,1,1,1,5,5,4,-1,-1,-2,-3,-1,-9};
int ans;
void dfs(int x,int step,int grade) // 当前在 x 级台阶,用了step步,得了grade分 
{
	if(x > 15 || step > 6) return ;
	
	if(x == 15) {
		ans = max(ans,grade);
		return ;
	}
	
	for(int i = 1 ; i <= 4 ; i++){
		dfs(x + i,step + 1,grade + score[x + i]);
	}
} 
int main(){
	
	dfs(0,0,0);
	cout << ans << endl;
	return 0;
}
  • JAVA
import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {

    public static Scanner sc = new Scanner(new BufferedInputStream(System.in));
    public static PrintStream ps = new PrintStream(System.out);

    public static int [] score = new int[]{0,1,2,1,1,1,1,5,5,4,-1,-1,-2,-3,-1,-9};
    public static int ans;
    public static void main(String[] args) {
        dfs(0,0,0);
        ps.println(ans);
    }

    private static void dfs(int x,int step,int grade) {
        if (x == 15) {
            ans = Math.max(ans,grade);
            return ;
        }

        for (int i = 1; i <= 4; i++) {
            if (x + i <= 15 && step <= 5)  dfs(x + i,step + 1, grade + score[i + x]);
        }
    }
}
剪邮票

题目链接

如下图, 有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。(仅仅连接一个角不算相连)

比如,下图中,粉红色所示部分就是合格的剪取。

剪邮票

请你计算,一共有多少种不同的剪取方法

AC代码

技巧

选不重复的方法

  • 从12个数中任意挑选5个数,用一个哈希表维护一个选取的数的记录,每次选取的数字都存入哈希表中,如果哈希表中已经存在该数字,则重新选择。

  • 可以先将12个数排序,然后从第一个数开始,每次挑选下一个数字即可,保证不会重复。

  • JAVA

    错误做法

    import java.io.BufferedInputStream;
    import java.io.PrintStream;
    import java.util.LinkedList;
    import java.util.Scanner;
    
    public class Main {
    
        public static Scanner sc = new Scanner(new BufferedInputStream(System.in));
        public static PrintStream ps = new PrintStream(System.out);
        public static LinkedList<Integer> path = new LinkedList<>();
        public static int [] vis = new int[15];
        public static int ans;
        public static void main(String[] args) {
           dfs(0,0);
           ps.println(ans);
        }
    
        private static void dfs(int x,int num) {
            if (num == 5){
                if (Check()) ans++;
                return ;
            }
    
            for (int i = x + 1; i <= 12; i++) {
                if (vis[i] == 0){
                    vis[i] = 1;
                    path.add(i);
                    dfs(i,num + 1);
    
                    vis[i] = 0;
                    path.removeLast();
                }
            }
    
        }
    
        private static boolean Check() {
            for (Integer item : path) {
                boolean flag = false;
    
                for (Integer item2 : path) {
                    if (item == item2) continue;
                    int abs = Math.abs(item - item2);
                    if (abs == 1 || abs == 4){  //在举例,会发现bug
                        flag = true;
                        break;
                    }
                }
                if (!flag) return false;
            }
            return true;
        }
    }
    
  • 正解

import java.io.BufferedInputStream;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
   

    public static Scanner sc = new Scanner(new BufferedInputStream(System.in));
    public static PrintStream ps = new PrintStream(System.out);
    public static LinkedList<Integer> path = new LinkedList<>();
    public static int [] vis = new int[15];
    public static int [] a = new int[] {
   1,
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值