数据结构与算法---回溯、剪枝

通过这节课,我们将学到:八皇后摆放问题、走迷宫的解法

回溯(Back Tracking)

这个英文单词可以的,”回去追踪”,回溯

回溯可以理解为:通过选择不同的岔口来通往目的地
每一步选择一条路出发,能进则进,不能进则退回上一步(回溯),换一条路再试
树、图的深度优先搜索就是典型的回溯应用

在这里插入图片描述
可以看出,回溯适合使用递归来解决。

知识的串联性,递归->回溯


八皇后问题(Eight Queens)

在一个8x8的国际象棋上,摆放八个皇后,使其不能相互攻击:
如果任意两个皇后处于同一行、同一列、同一斜线,则会发生攻击。
也就是,任意两个皇后,不能处于同一行、同一列、同一斜线
问:有多少种摆法?

八皇后解题思路

方法一:暴力法
从64个格子中,任意选出8个摆放,选出符合条件的摆法。

方法二:优化后的暴力法
每一行只能放一个

方法三:回溯+剪枝

剪枝(Pruning)

在这里插入图片描述

package com.yz;

public class Main {
	public static void main(String[] args) {
		new Main().placeQueens(4);
	}
		
	/**
	 * cols[row] = col
	 * 第row行存放的皇后在第col列
	 * */
	int[] cols;
	//有多少种摆法
	int ways;
	
	/**摆放n皇后*/
	void placeQueens(int n)
	{
		if(n < 1) return;
		cols = new int[n];
		place(0);
		System.out.println(n + "皇后一共有" + ways + "种摆法");
	}
	
	/**从第row行开始摆放皇后*/
	void place(int row)
	{
		if (row == cols.length) {
			ways++;
			show();
			return;
		}
		
		for (int col = 0; col < cols.length; col++) {
			if (isValid(row, col)) {
				cols[row] = col;
				place(row + 1);
			}
		}
	}
	
	/**
	 * 判断第row行,第col列能否摆放皇后
	 * */
	boolean isValid(int row, int col)
	{
		for (int i = 0; i < row; i++) {
			//第col列已经有皇后
			if (cols[i] == col) return false;
			//判断斜线
			if(row - i == Math.abs(col - cols[i])) return false;
		}
		return true;
	}
	
	/**
	 * 打印
	 * */
	void show()
	{	
		for (int row = 0; row < cols.length; row++) {
			for (int col = 0; col < cols.length; col++) {
				if (cols[row] == col) {
					System.out.print("1 ");
				}else{
					System.out.print("0 ");
				}
			}
			System.out.println();
		}
		System.out.println("------------");
	}
}

优化

在判断某一位置是否可以放皇后的时候,我们需要遍历之前所有row的情况,找出该点相关的列与该列是否相同。
我们其实只需要知道某一点的某列上是否存在皇后即可,并不需要知道已存在皇后的具体位置。
也就是int[] cols;可以修改为boolean[] cols;

同理,可以使用一个数组表示某一格子的斜线是否有皇后。

内存空间的优化

但是,这种做法,只能求出有多少种摆放方法,并不能具体打印出如何摆放。

因此,不做代码展示,以上面代码为准。

还可以通过位运算优化代码(不做阐述)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值