深度优先搜索练习

深度优先搜索练习

题目一 : 全排列问题1

题目描述

输出自然数 1n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 n

输出格式

1 ∼ n 1 \sim n 1n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5个场宽。

输入输出样例

输入 #1

3

输出 #1

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

说明/提示

1 ≤ n ≤ 9 1\le n \le 9 1n9

//代码:
import java.util.Scanner;
public class Main{
	static int n;
	static int[] a = new int[10],book = new int[10];
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		n = scan.nextInt();
		dfs(1);
	}	
	public static void dfs(int step){
		if (step > n){
			for (int i = 1 ; i <= n ; i++ ) 
				System.out.print("    "+a[i]);//场宽5
			System.out.print("\n");
			return;
		}
		for (int k = 1 ; k <= n ; k++ ) {
			if (book[k] == 0) {
				a[step] = k;
				book[k] = 1;
				dfs(step+1);
				book[k] = 0;
			}
		}
		return;
	}
}

DFS入门题



题目二 : 八皇后2

题目描述

一个如下的 6×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
洛谷-八皇后

上面的布局可以用序列 2 4 6 1 3 5 来描述,第 i 个数字表示在第 i 行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。

输入格式

一行一个正整数 n,表示棋盘是 n×n 大小的。

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

输入输出样例

输入 #1

6

输出 #1

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

说明/提示

【数据范围】对于 100% 的数据,6 ≤ n ≤ 13

//代码:
import java.util.Scanner;
public class Main{
	static final int N = 100;
	static int n,max,mark;
	static int[] a = new int[N] , col = new int[N] , d = new int[N], ud = new int[N];
    
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		n = scan.nextInt();
		dfs(1);
		System.out.print(max);
	}
	public static void dfs(int step){
		if (step > n) {
			if (mark < 3) {
				for (int i = 1 ; i <= n ; i++ ){
					System.out.print(a[i]+" ");
				}
				mark++;
				System.out.print("\n");
			}
			max++;
			return;	
		}
		for (int k = 1; k <= n ; k++) {
			int t1 = step + k - 1;
			int t2 = n + step - k;
			if (col[k] == 0 && d[t1] == 0 && ud[t2] == 0) {
				col[k] = d[t1] = ud[t2] = 1;
				a[step] = k;
				dfs(step+1);
				col[k] = d[t1] = ud[t2] = 0;
			}
		}
	}
}

经典题目



题目3 : 2n皇后问题3

题目描述

给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

输入

输入的第一行为一个整数n,表示棋盘的大小。

接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。

输出

输出一个整数,表示总共有多少种放法。

样例输入

4
1 1 1 1 
1 1 1 1 
1 1 1 1 
1 1 1 1 

样例输出

2
//代码:
import java.util.Scanner;
public class Main{

	static final int N = 20;
	static int n , max = 0;
	static int[][] book = new int[N][N];
	static int[] col = new int[N] , di = new int[N] , ud = new int[N];
	static int[] col2 = new int[N] , di2 = new int[N] , ud2 = new int[N];
    
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		n = scan.nextInt();
		for (int i = 1 ; i <= n  ; i++)
			for (int j = 1 ; j <= n ; j++ )
				book[i][j] = scan.nextInt();
		dfs(1);
		System.out.println(max);
	}

	public static void dfs(int step){
		if (step > n) {
			dfs2(1);
			return;
		}
		for (int k = 1 ; k <= n ; k++ ) {
			int t1 = step + k - 1;
			int t2 = n + step - k;
			if ( book[step][k] == 1 && di[t1] == 0 && ud[t2] == 0 && col[k] == 0 ) {
				book[step][k] = 0;
				di[t1] = ud[t2] = col[k] = 1;
				dfs(step+1);  
				book[step][k] = 1;
				di[t1] = ud[t2] = col[k] = 0;
			}       
		}
	}
	public static void dfs2(int step){
		if (step > n) {
			max++;
			return;
		}
		for (int k = 1 ; k <= n ; k++ ) {
			int t1 = step + k - 1;
			int t2 = n + step - k;
			if ( book[step][k] == 1 && di2[t1] == 0 && ud2[t2] == 0 && col2[k] == 0 ) {
				book[step][k] = 0;
				di2[t1] = ud2[t2] = col2[k] = 1;
				dfs2(step+1);
				book[step][k] = 1;
				di2[t1] = ud2[t2] = col2[k] = 0;
			}
		}
	}
}

n皇后问题的变种,使用二次dfs简化难度



  1. 题目来源-https://www.luogu.com.cn/problem/P1706 ↩︎

  2. 题目来源-https://www.luogu.com.cn/problem/P1219 ↩︎

  3. 题目来源-https://www.dotcpp.com/oj/problem1460.html ↩︎

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值