递归——八皇后问题

1,前言

8x8的棋盘,放8个棋子。
各自不能在同一直线上。(水平方向,对角线方向)

在线游玩:https://www.novelgames.com/zh/queens/

2,JS实现

let size = 8
let count = 0
loopTo([], 0)
function loopTo(arr, v) {
    
    
	if (arr.length === size) {
    
    
		console.log(++count + "[" + arr.toLocaleString() + "]")
		loopBack(arr)
	} else if (canPut(arr, v)) {
    
    
		arr.push(v)
		loopTo(arr, 0)
	} else if (v < size - 1) {
    
    
		loopTo(arr, v + 1)
	} else {
    
    
		setTimeout(() => {
    
    
			loopBack(arr)
		}, 1)
	}
}
function loopBack(arr) {
    
    
	let v = arr.pop()
	while (v !== undefined && v >= size - 1) {
    
    
		v = arr.pop()
	}
	if (v === undefined) {
    
    
		console.log("无解")
	} else {
    
    
		loopTo(arr, v + 1)
	}
}
function canPut(arr, v) {
    
    
	for (let m = 0; m <= arr.length - 1; m++) {
    
    
		if (arr[m] === v) {
    
    
			return false
		} else if (arr.length - m === v - arr[m]) {
    
    
			return false
		} else if (arr.length - m === arr[m] - v) {
    
    
			return false
		}
	}
	return true
}

效果:算到92,然后再无其他解。

在这里插入图片描述

3,细节实现

验证结果的有效性

比较结果的长度。
两层遍历,比较棋子与之前的所有棋子位置是否符合。

function checkResult(arr) {
    
    
	if (arr.length !== size) {
    
    
		return false
	}
	for (let i = 1; i < size; i++) {
    
    
		for (let j = 0; j < i; j++) {
    
    
			if (arr[i] === arr[j]) {
    
    
				return false
			} else if (Math.abs(i - j) === Math.abs(arr[i] - arr[j])) {
    
    
				return false
			}
		}
	}
	return true
}

验证是否可以加入数组

位置符合就true,不符合false。

function canPut(arr, v) {
    
    
	for (let m = 0; m <= arr.length - 1; m++) {
    
    
		if (arr[m] === v) {
    
    
			return false
		} else if (Math.abs(arr.length - m) === Math.abs(v - arr[m])) {
    
    
			return false
		}
	}
	return true
}

回退

如果到了最大值还不满足,就会回退。

没元素说明无解。

栈顶元素大小到了最大值,继续回退。
否则就加一,重新尝试。

扫描二维码关注公众号,回复: 13759851 查看本文章
function loopBack(arr) {
    
    
	if (arr.length === 0) {
    
    
		console.log("无解")
		return
	}
	let v = arr.pop()
	if (v >= size - 1) {
    
    
		loopBack(arr)
	} else {
    
    
		loopTo(arr, v + 1)
	}
}

主循环

加定时器是为了避免堆栈溢出。。。
(奇怪的用途增加了!)

如果长度足够,就说明已经放满了。
输出,然后回退。

如果能入,就入。然后继续。
如果不能入,判断值,太大了就回退,不大就加一。

function loopTo(arr, v) {
    
    
	setTimeout(() => {
    
    
		if (arr.length === size) {
    
    
			console.log(++count + "[" + arr.toLocaleString() + "]" + checkResult(arr))
			loopBack(arr)
		} else if (canPut(arr, v)) {
    
    
			arr.push(v)
			loopTo(arr, 0)
		} else if (v < size - 1) {
    
    
			loopTo(arr, v + 1)
		} else {
    
    
			loopBack(arr)
		}
	}, 1)
}

番外:更多皇后

九皇后。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_37284843/article/details/123860105