当前位置:网站首页>八皇后编程实现
八皇后编程实现
2022-07-27 00:02:00 【江北-科技】
八皇后问题说明
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于 1848 年
提出:在 8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法
回溯算法思路
八皇后问题如果用穷举法需要尝试88=16,777,216种情况。每一列放一个皇后,可以放在第 1 行,第 2 行,……,直到第8行。穷举的时候从所有皇后都放在第1行的方案开始,检验皇后之间是否会相互攻击。如果会,把列H的皇后挪一格,验证下一个方案。移到底了就“进位”到列G的皇后挪一格,列H的皇后重新试过全部的8行。这种方法是非常低效率的,因为它并不是哪里有冲突就调整哪里,而是盲目地按既定顺序枚举所有的可能方案。
回溯算法优于穷举法。将列A的皇后放在第一行以后,列B的皇后放在第一行已经发生冲突。这时候不必继续放列C的皇后,而是调整列B的皇后到第二行,继续冲突放第三行,不冲突了才开始进入列C。如此可依次放下列A至E的皇后。将每个皇后往右边横向、斜向攻击的点位用叉标记,发现列F的皇后无处安身。这时回溯到列E的皇后,将其位置由第4行调整为第8行,进入列F,发现皇后依然无处安身,再次回溯列E。此时列E已经枚举完所有情况,回溯至列D,将其由第2行移至第7行,再进入列E继续。按此算法流程最终找到如图3所示的解,成功在棋盘里放下了8个“和平共处”的皇后。继续找完全部的解共92个。
回溯算法求解八皇后问题的原则是:有冲突解决冲突,没有冲突往前走,无路可走往回退,走到最后是答案。为了加快有无冲突的判断速度,可以给每行和两个方向的每条对角线是否有皇后占据建立标志数组。放下一个新皇后做标志,回溯时挪动一个旧皇后清除标志。

编程实现
Haskall
queens :: Int -> [[Int]]
queens n = map reverse $ queens' n
where queens' 0 = [[]]
queens' k = [q:qs | qs <- queens' (k-1), q <- [1..n], isSafe q qs]
isSafe try qs = not (try `elem` qs || sameDiag try qs)
sameDiag try qs = any (\(colDist,q) -> abs (try - q) == colDist) $ zip [1..] qs
GO
package main
import "fmt"
func main() {
var balance = [8]int{
0, 0, 0, 0, 0, 0, 0, 0}
queen(balance, 0)
}
func queen(a [8]int, cur int) {
if cur == len(a) {
fmt.Print(a)
fmt.Println()
return
}
for i := 0; i < len(a); i++ {
a[cur] = i
flag := true
for j := 0; j < cur; j++ {
ab := i - a[j]
temp := 0
if ab > 0 {
temp = ab
} else {
temp = -ab
}
if a[j] == i || temp == cur-j {
flag = false
break
}
}
if flag {
queen(a, cur+1)
}
}
}
JS
function queen(a, cur) {
if (cur==a.length) {
console.log(a); return; }
for (var i = 0; i < a.length; i++) {
a[cur] = i;
var flag = true;
for (var j = 0; j < cur; j++) {
var ab = i - a[j];
if (a[j]==i||(ab>0?ab:-ab)==cur-j) {
flag=false; break };
};
if (flag) {
queen(a,cur+1); }
};
};
queen([1,1,1,1,1,1,1,1],0);
C++
#include <iostream>
using namespace std;
const int N = 8;
int arr[10], total_cnt;
// arr记录每一行(X)皇后的Y坐标
bool isPlaceOK(int *a, int n, int c) {
for (int i = 1; i <= n - 1; ++i) {
if (a[i] == c || a[i] - i == c - n || a[i] + i == c + n)
return false;
//检查位置是否可以放
//c是将要放置的位置
//a[i] == c如果放在同一列,false
//a[i] -+ i = c -+ n 如果在对角线上,false
}
return true;
}
void printSol(int *a) {
for (int i = 1; i <= N; ++i) {
//遍历每一行
for (int j = 1; j <= N; ++j) {
//遍历每一列
cout << (a[i] == j ? "X" : "-") << " ";;
} //如果标记数组中这一行的皇后放在j位置,则输出X,否则输出-,
//用空格分隔
cout << endl; //每一行输出一个换行
}
cout << endl; //每一组数据一个换行分隔
}
void addQueen(int *a, int n) {
if (n > N) {
//n代表从第一行开始放置
printSol(a);
total_cnt++;
return ;
}
for (int i = 1; i <= N; ++i) {
//i从第1列到第N列遍历
if (isPlaceOK(a, n, i)) {
a[n] = i; //如果可以放置,就把皇后放在第n行第i列
addQueen(a, n + 1);
}
}
}
int main() {
addQueen(arr, 1);
cout << "total: " << total_cnt << " solutions.\n";
return 0;
}
Pascal
program queen; var a:array[1…8]of longint; //记录皇后的行坐标
b,c,d:array[-7…16]of longint; //行,右上,右下斜线的占位标志 m,ans:longint;
procedure queen(j:longint); var i:longint; begin
if j>8 then
begin
inc(ans); //满足条件,找到一种方案
exit;
end;
for i:=1 to 8 do//每个皇后位置有八种可能
if(b[i]=0)and(c[i+j]=0)and(d[j-i]=0)then //如果位置没有被占则运行
begin
a[j]:=i; //皇后放置在此行
b[i]:=1; //占领第i行
c[i+j]:=1; //占领右上
d[j-i]:=1; //占领右下
queen(j+1); //递归
b[i]:=0; //回溯,恢复行占位标志
c[i+j]:=0; //回溯,恢复斜上方(右上)占位标志
d[j-i]:=0; ///回溯,恢复斜下方(右下)占位标志
end; end; begin //主程序
for m:=-7 to 16 do //数据初始化为0
begin
b[m]:=0; //行数据初始化为0
c[m]:=0; //右上数据初始化为0
d[m]:=0; //右下数据初始化为0
end;
ans:=0;
queen(1); //开始放置第一个皇后
writeln(ans); end.
Java
public class Queen {
private int[] column; //同栏是否有皇后,1表示有
private int[] rup; //右上至左下是否有皇后
private int[] lup; //左上至右下是否有皇后
private int[] queen; //解答
private int num; //解答编号
public Queen() {
column = new int[8+1];
rup = new int[(2*8)+1];
lup = new int[(2*8)+1];
for (int i = 1; i <= 8; i++)
column[i] = 0;
for (int i = 1; i <= (2*8); i++)
rup[i] = lup[i] = 0; //初始定义全部无皇后
queen = new int[8+1];
}
public void backtrack(int i) {
if (i > 8) {
showAnswer();
} else {
for (int j = 1; j <= 8; j++) {
if ((column[j] == 0) && (rup[i+j] == 0) && (lup[i-j+8] == 0)) {
//若无皇后
queen[i] = j; //设定为占用
column[j] = rup[i+j] = lup[i-j+8] = 1;
backtrack(i+1); //循环调用
column[j] = rup[i+j] = lup[i-j+8] = 0;
}
}
}
}
protected void showAnswer() {
num++;
System.out.println("\n解答" + num);
for (int y = 1; y <= 8; y++) {
for (int x = 1; x <= 8; x++) {
if(queen[y]==x) {
System.out.print("Q");
} else {
System.out.print(".");
}
}
System.out.println();
}
}
public static void main(String[] args) {
Queen queen = new Queen();
queen.backtrack(1);
}
}
Erlang
-module(queen).
-export([printf/0, attack_range/2]).
-define(MaxQueen, 4).%寻找字符串所有可能的排列
%perms([]) ->% [[]];
%perms(L) ->% [[H | T] || H <- L, T <- perms(L -- [H])].
perms([]) ->[[]];
perms(L) ->[[H | T] || H <- L, T <- perms(L -- [H]), attack_range(H,T) == []].printf() ->L = lists:seq(1, ?MaxQueen),io:format("~p~n", [?MaxQueen]),perms(L).
%检测出第一行的数字攻击到之后各行哪些数字%left向下行的左侧检测%right向下行的右侧检测
attack_range(Queen, List) ->attack_range(Queen, left, List) ++ attack_range(Queen, right, List).attack_range(_, _, []) ->[];
attack_range(Queen, left, [H | _]) when Queen - 1 =:= H ->[H];
attack_range(Queen, right, [H | _]) when Queen + 1 =:= H ->[H];
attack_range(Queen, left, [_ | T]) ->attack_range(Queen - 1, left, T);attack_range(Queen, right, [_ | T]) ->attack_range(Queen + 1, right, T).
python
def queen(A, cur=0):
if cur == len(A):
print(A)
return 0
for col in range(len(A)): # 遍历当前行的所有位置
A[cur] = col
for row in range(cur): # 检查当前位置是否相克
if A[row] == col or abs(col - A[row]) == cur - row:
break
else: # 如果完成了整个遍历,则说明位置没有相克
queen(A, cur+1) # 计算下一行的位置
queen([None]*8)
C#
using System;
using System.Collections.Generic;
namespace EightQueens_CSharp {
public class EightQueens {
private List<int[]> solutions;
public List<int[]> GetSolutions(int queenCount) {
solutions = new List<int[]>();
List<int> queenList = new List<int>();
for (int i = 0; i < queenCount; i++) {
queenList.Add(0);
}
putQueen(queenCount, queenList, 0);
printSolutions(solutions);
return solutions;
}
private void putQueen(int queenCount, List<int> queenList, int nextY) {
for (queenList[nextY] = 0; queenList[nextY] < queenCount; queenList[nextY]++) {
if (checkConflict(queenList, nextY) == false) {
nextY++;
if (nextY < queenCount) {
putQueen(queenCount, queenList, nextY);
}
else {
solutions.Add(queenList.ToArray());
Console.WriteLine(string.Join(", ", queenList));
}
nextY--;
}
}
}
private bool checkConflict(List<int> queenList, int nextY) {
for (int positionY = 0; positionY < nextY; positionY++) {
if (Math.Abs(queenList[positionY] - queenList[nextY]) == Math.Abs(positionY - nextY) || queenList[positionY] == queenList[nextY]) {
return true;
}
}
return false;
}
private void printSolutions(List<int[]> solutions) {
int count = 0;
foreach (var solution in solutions) {
Console.WriteLine("Solution: {0}", count++);
int queenCount = solution.Length;
for (int i = 0; i < queenCount; i++) {
printLine(solution[i], queenCount);
}
Console.WriteLine("------------------");
}
}
private void printLine(int pos, int width) {
for (int i = 0; i < width; i++) {
if (pos == i) {
Console.Write(" x");
}
else {
Console.Write(" .");
}
}
Console.WriteLine();
}
}
}
Scheme
#lang racket (define (enumerate-interval low high) (cond ((> low high) null)
((= low high) (list high))
(else (cons low (enumerate-interval (+ 1 low) high)))))
(define (flatmap proc seq) (foldr append null (map proc seq)))
(define empty-board null)
(define (safe? test-column positions) (define (two-coordinate-safe? coordinate1 coordinate2)
(let ((row1 (row coordinate1))
(row2 (row coordinate2))
(col1 (column coordinate1))
(col2 (column coordinate2)))
(if (or (= row1 row2)
(= (abs (- row1 row2)) (abs (- col1 col2))))
#f
#t))) (let ((test-coordinate (get-coordinate-by-column test-column positions)))
(foldr (lambda (coordinate results)
(and (two-coordinate-safe? test-coordinate coordinate)
results))
#t
(remove test-coordinate positions))))(define (adjoin-position new-row new-column existing-positions) (cons (make-coordinate new-row new-column)existing-positions))
(define (make-coordinate row column) (list row column)) (define (row coordinate) (car coordinate)) (define (columncoordinate) (cadr coordinate)) (define (get-coordinate-by-column
target-column coordinates) (cond ((null? coordinates) null)
((= target-column (column (car coordinates))) (car coordinates))
(else (get-coordinate-by-column target-column (cdr coordinates)))))(define (queens board-size) (define (queen-cols k) (if (= k 0) (list empty-board) (filter (lambda (positions) (safe? k positions)) (flatmap (lambda (rest-of-queens) (map (lambda (new-row) (adjoin-position new-row k rest-of-queens)) (enumerate-interval 1 board-size))) (queen-cols (- k 1)))))) (queen-cols board-size)) ;敲(queens 8),得到运行结果,每个坐标,第一个代表行,第二个代表列 ;纯递归思路,运行环境racket 7.5
Lua
local num = 0;
local t = socket.gettime();
local function searchQueen(tab)
local data = clone(tab)
if data[2] == #data[1] then
num = num + 1
-- return print("result..", num, " ==> ", table.concat(data[1], ","))
return
end
data[2] = data[2] + 1;
for i = 1, 8 do
data[1][data[2]] = i
local bOk = true
for j = 1, data[2]-1 do
if (data[1][j] == i) or (math.abs(i - data[1][j]) == data[2] - j) then
bOk = false
break
end
end
if bOk then
searchQueen(data)
end
end
end
searchQueen({
{
0,0,0,0,0,0,0,0}, 0})
print("EIGHT QUEEN result == ", num, "\ntime cost == ", socket.gettime() - t)
边栏推荐
猜你喜欢

C language: deep learning recursion

Kubernetes Dashboard 部署应用以及访问

贪心——376. 摆动序列

系统安全测试要怎么做,详细来说说

I was fired at the age of 30. I want to understand a few things

「软件测试」包装简历从这几点出发,直接提升通过率

【Redis】快速入门

F8 catch traffic, F9 catch rabbits, f10turttle

Graduated and entered HW, from test engineer to project manager. Now I earn millions in goose factory every year. My suggestions to you

Okaleido tiger is about to log in to binance NFT in the second round, which has aroused heated discussion in the community
随机推荐
信息收集-端口扫描工具-Nmap使用说明
Shell 分析日志文件命令全面总结
C language program compilation
文章主要内容提取软件[基于NLP技术]
[untitled]
Debezium series: the binlog file cannot be recovered after the record is hung from the library server, and the task is switched to the main library to ensure that the data is not lost
c语言:深度学习递归
Heisei thousand words (Heisei, September 10, 2012) (Shidu Mingzuo) the universe is far away, the Milky way is permanent, the sun and moon are running disorderly, the earth is open, the seasons shift,
面试突击68:为什么 TCP 需要 3 次握手?
[Li Kou] 1859. Sort sentences
银河证券基金低佣金开户靠谱吗,可靠安全吗
I wish you a happy Chinese Valentine's day and invite you to read the source code together
Kubernetes Dashboard 部署应用以及访问
Knowledge points of test questions related to software testing
【Redis】快速入门
LeetCode->二分查找打卡(三)
次轮Okaleido Tiger即将登录Binance NFT,引发社区热议
If you want to thoroughly optimize the performance, you must first understand the underlying logic~
贪心——376. 摆动序列
Quick sort