【蓝桥备战】DFS

39 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

DFS

深度优先搜索。以二叉树为例,只有当前节点不能继续遍历时,才会往回退,否则就继续搜索。 使用栈这种数据结构实现。空间复杂度为O(n)。不具有“最短路径”的性质。 把握两个概念:回溯、剪枝。DFS考虑顺序,类似递归,考虑dfs函数的意义。

全排列数字

使用dfs算法,使用path数组保存结果,使用used数组判断数字是否使用。明确每一层要做的事情:

  1. 判断当前数字是否使用,如果没有使用,就使用当前数字。
  2. 每次回溯时恢复原状态。
import java.util.Scanner;

public class Main {
	static int N = 10;
	//使用path保存全排列数。
	static int path[];
	static boolean used[];
	static int n;
	public static void main(String[] args) {
		Scanner s = new Scanner (System.in);
		n = s.nextInt();
		path = new int [n];
		used = new boolean [n + 1];
		dfs(0);
	}
	static void dfs(int u) {
		//如果u是n,说明当前已经排好了n个数字,输出即可。
		if(u == n) {
			for(int i = 0;i<n;i++) {
				System.out.print(path[i] + " ");
			}
			System.out.println();
		}
		//寻找当前没有使用的数字。
		for(int i = 1;i<=n;i++) {
			//如果当前数字没有使用,则使用当前数字,继续深度搜索。
			if(!used[i]) {
				path[u] = i;
				used[i] = true;
				dfs(u + 1);
				used[i] = false;
			}
		}
	}
}

八皇后问题

解法一:类似全排列的思想。**按行进行dfs。**不用考虑同一行的问题。

import java.util.Scanner;

public class Main {
	static int N = 20;
	static char grp[][];
	static int n;
	static boolean col[] = new boolean [N];
	static boolean dg[] = new boolean [N];
	static boolean udg[] = new boolean [N];
	public static void main(String[] args) {
		Scanner s = new Scanner (System.in);
		n = s.nextInt();
		grp  = new char [n][n];
		for(int i = 0;i<n;i++) {
			for(int j = 0;j<n;j++) {
				grp[i][j] = '.';
			}
		}
		dfs(0);
		}
		
	static void dfs(int row) {
		if(row == n) {
			for(int i = 0;i<n;i++) {
				System.out.println(grp[i]);
			}
			System.out.println();
			return;
		}
		
		//判断该行的每列位置是否合法。合法——不在同一列、同一斜线、同一直线。
		for(int coll = 0;coll<n;coll++) {
			//每一条对角线对应唯一截距:反对角线:y = x + b  截距:b = y - x
			//						对角线:y = -x + b 截距:b = y + x
			if(!col[coll] && !dg[row + coll] && !udg[n + coll - row]) {
				grp[row][coll] = 'Q';
				col[coll] = dg[row + coll] = udg[n + coll - row] =  true;
				dfs(row + 1);
				grp[row][coll] = '.';
				col[coll] = dg[row + coll] = udg[n + coll - row] =  false;
			}
		}
	}
}

解法二:把每一个格子都分为两种状态【放(满足条件时)/不放(不需要条件)】。 当满足x为最后的一行并且皇后数量等于n时,才会输出答案。

import java.util.Scanner;

public class Main {
	static int N = 20;
	static int n;
	static char grp[][];
	static boolean row [] = new boolean [N];
	static boolean colum [] = new boolean [N];
	static boolean bg []  = new boolean [N];
	static boolean ubg []  = new boolean [N];
	public static void main(String[] args) {
		Scanner s = new Scanner (System.in);
		n = s.nextInt();
		grp = new char [n][n];
		dfs(0,0,0);
	}
	static void dfs(int x,int y,int s) {
		//当前行全部走了一遍,跳到下一行。
		if(y == n) {
			x ++;
			y = 0;
		}
		//走到了最后一行
		if(x == n) {
			//此时的皇后数等于n的数量,即为符合条件
			if(s == n) {
				for(int i = 0;i<n;i++) {
					System.out.println(grp[i]);
				}
				System.out.println();
			}
			return ;
		}
		
		//当前格子不放皇后
		grp[x][y] = '.';
		dfs(x,y + 1,s);
		
		//当前格子放皇后
		if(!row [x] && !colum[y] && !bg[x + y] && !ubg[n + x - y]) {
			row[x] = colum[y] = bg[x + y] = ubg[n + x - y] = true;
			grp[x][y] = 'Q';
			dfs(x,y + 1,s + 1);
			row[x] = colum[y] = bg[x + y] = ubg[n + x - y] = false;
			grp[x][y] = '.';
		}
		
	}
}