八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。
该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
计算机发明后,有多种方法可以解决此问题。

2010年,在写完中国象棋的核心模块后,当时添加了一个扩展应用模块,N皇后问题。

效果图

算法源码

下面是控制台程序的源码。

/**
* 项目名称: FansChineseChess
* 版本号:2.0
* 名字:雷文
* 博客: http://FansUnion.cn
* CSDN:http://blog.csdn.net/FansUnion
* 邮箱: leiwen@FansUnion.cn
* QQ:240-370-818
* 版权所有: 2011-2013,leiwen
*/
package cn.fansunion.chinesechess.ext.empress; import java.awt.Point;
import java.util.ArrayList;
import java.util.List; /**
* 求N皇后的所有合法布局
*
* 3个约束条件:任何2个棋子都不能占居棋盘上的同一行、或者同一列、或者同一对角线。
*
* 棋盘状态的变化情况,可以看作一个N叉树。
*
* 求所有合法布局的过程,即为在3个约束条件下先根遍历状态树的过程。
*
* 遍历中访问结点的操作为,判断棋谱上是否已经得到一个完整的布局,如果是,则输出该布局;
*
* 否则依次先根遍历满足约束条件的各棵子树,即首先判断该子树根的布局是否合法,若合法,则
*
* 先根遍历该子树,否则减去该子树分支。
*
* @author leiwen@fansunion.cn,http://FansUnion.cn,
* http://blog.csdn.net/FansUnion
* @since 2.0
*/
public class EmpressModel { /**
* 皇后的个数
*/
private int num;
/**
* 棋盘数据结构
*/
private int[][] array;
/**
* 棋盘中的布局集合,每一种布局采用简写形式
*/
private List<ArrayList<Point>> lists = new ArrayList<ArrayList<Point>>();
/**
* 棋盘中的布局集合,每一种布局采用完整形式
*/
private List<int[][]> advancedLists = new ArrayList public EmpressModel(int n) {
this.num = n;
array = new int[n + 1][n + 1];// 默认为0
} // 初始化所有的布局
public void initAllLayout() {
trial(1);
sort();
initAdvancedLists();
} /**
* 进入本函数时,在n*n棋盘前j-1列已经放置了满足3个条件的j-1个棋子
*
* 现在从第j列起,继续为后续棋子选择合适的位置
*
* 选择列优先,是为了保证在GUI显示布局的变化,看起来是,每一行的棋子都是从左向右移动的。
*
* 行优先时,每列棋子,从上向下移动。
*
* @param j
*/
private void trial(int j) {
// 进入本函数时,在n*n棋盘前j-1列已经放置了满足3个条件的j-1个棋子
// 现在从第i行起,继续为后续棋子选择合适的位置
if (j > num) {
// 求得一个合法布局,保存起来
saveCurrentLayout();
} else {
for (int i = 1; i <= num; i++) {
// 在第i行第j列放置一个棋子
array[i][j] = 1;
if (isLegal(i, j)) {
trial(j + 1);
}
// 移走第i行第j列的棋子
array[i][j] = 0;
}
}
} /**
* 判断当前布局是否合法
*
* @return
*/
private boolean isLegal(int row, int col) { for (int i = 1; i < array.length; i++) {
int sumI = 0;// 第i行之和
int sumJ = 0;// 第i列之和
for (int j = 1; j < array[i].length; j++) {
sumI += array[i][j];
sumJ += array[j][i];
}
if (sumI >= 2 || sumJ >= 2) {
return false;
}
sumI = 0;
sumJ = 0; } // 左上到右下的对角线是否有棋子
int i = row - 1;
for (int j = col - 1; j >= 1; j--) {
if (i >= 1 && array[i][j] == 1) {
return false;
}
i--;
} // 左下到右上的对角线是否有棋子
i = row + 1;
for (int j = col - 1; j >= 1; j--) {
if (i <= this.num && array[i][j] == 1) {
return false;
}
i++;
} return true;
} /**
* 保存当前的布局
*/
private void saveCurrentLayout() {
ArrayList<Point> list = new ArrayList<Point>();
for (int i = 1; i < array.length; i++) {
for (int j = 1; j < array[i].length; j++) {
if (array[i][j] == 1) {
list.add(new Point(i, j));
}
}
}
lists.add(list);
} /**
* 打印所有的布局(最简形式)
*/
public void printBasicLayout() {
int size = lists.size();
for (int i = 0; i < size; i++) {
ArrayList<Point> arrayList = lists.get(i);
int size2 = arrayList.size();
System.out.println("第" + i + "种布局!");
for (int j = 0; j < size2; j++) {
Point point = arrayList.get(j);
System.out.print("(" + (int) point.getX() + ","
+ (int) point.getY() + ")\t");
}
System.out.println();
}
System.out.println();
} /**
* 打印所有的布局(高级形式)
*/
public void printAddvancedLayout() {
int size = advancedLists.size();
for (int i = 0; i < size; i++) {
int[][] arr = advancedLists.get(i);
System.out.println("第" + i + "种布局!");
for (int j = 1; j <= num; j++) {
for (int k = 1; k <= num; k++) {
System.out.print(arr[j][k] + "\t");
}
System.out.println();
}
System.out.println();
}
System.out.println();
} /**
* 排序是为了,减少抖动,即每次变换布局时,近可能少地换棋子 (每次切换到下一个布局时,棋子的变换尽可能少,视觉上棋子在有规律的移动)
*/
public void sort() {
sortEveryList();
} private void sortEveryList() {
/*
* System.out.println("冒泡排序之前:"); printAllLayout();
*/
int size = lists.size();
// 对lists中的每个链表,按照点的纵坐标排序
for (int q = 0; q < size; q++) { ArrayList<Point> arraylist = lists.get(q); int size2 = arraylist.size();
// 冒泡排序
for (int r = 1; r < size2; r++) {
// 纵坐标从小到大
for (int s = 0; s < size2 - r; s++) {
Point first = arraylist.get(s);
double m = first.getY(); Point second = arraylist.get(s + 1);
double n = second.getY(); if (m > n) {
arraylist.set(s + 1, first);
arraylist.set(s, second);
} }
}
} } private void initAdvancedLists() {
int size = lists.size();
for (int index = 0; index < size; index++) {
ArrayList<Point> list = lists.get(index);
int[][] arr = new int[num + 1][num + 1]; int len = list.size();
for (int i = 0; i < len; i++) {
int x = (int) list.get(i).getY();
int y = (int) list.get(i).getX();
arr[x][y] = 1;
} advancedLists.add(arr);
}
} public int[][] getArray() {
return array;
} public int getNum() {
return num;
} public List<ArrayList<Point>> getLists() {
return lists;
} public List<int[][]> getAdvancedLists() {
return advancedLists;
} public static void main(String[] args) {
EmpressModel em4 = new EmpressModel(4);
em4.initAllLayout();
em4.printBasicLayout();
// 初始化高级保存需要的布局
//em4.initAdvancedLists();
em4.printAddvancedLayout(); } }

设计思想

算法(模型)和界面相分离。

算法构造数据,界面展示数据。

展示分2种:中国象棋棋盘中和控制台中。

源码出处

本算法源码摘自 http://blog.csdn.net/fansunion/article/details/11787413

中国象棋程序-源码,扩展应用模块--N皇后

原文参见:http://FansUnion.cn/articles/2684

中国象棋程序的设计与实现(六)--N皇后问题的算法设计与实现(源码+注释+截图)的更多相关文章

  1. JavaScript中国象棋程序(1) - 界面设计

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第1节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  2. 中国象棋程序的设计与实现(十一)--第2次回答CSDN读者的一些问题

    最近一段时间,有不少CSDN读者朋友看了我写的中国象棋文章.其中,不少爱好者下载了中国象棋程序的初级版和高级版源码. 由于水平有限,不少同学遇到了若干问题,向我咨询,寻找解决办法. 我的处境1.如果我 ...

  3. JavaScript中国象棋程序(0) - 前言

    “JavaScript中国象棋程序” 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.希望通过这个系列,我们对博弈程序的算法有一定的了解.同时,我们也将构建出一个不错的中国象棋程序 ...

  4. JavaScript中国象棋程序(2) - 校验棋子走法

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第2节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  5. JavaScript中国象棋程序(3) - 电脑自动走棋

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第3节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  6. JavaScript中国象棋程序(4) - 极大极小搜索算法

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第4节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  7. JavaScript中国象棋程序(5) - Alpha-Beta搜索

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第5节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  8. JavaScript中国象棋程序(6) - 克服水平线效应、检查重复局面

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第6节. 这一系列共有9个部分: 0.JavaScript中国象 ...

  9. JavaScript中国象棋程序(7) - 置换表

    "JavaScript中国象棋程序" 这一系列教程将带你从头使用JavaScript编写一个中国象棋程序.这是教程的第2节. 这一系列共有9个部分: 0.JavaScript中国象 ...

随机推荐

  1. luoguP1002

    p1002 题意: 从坐标A到坐标B的可能路线(有一些点不能走)情况,很明显可以看出用dp做 m[i][j]=m[i-1][j]+m[i][j-1](注意处理不能走的点) 自己在初始化时犯了错,第1行 ...

  2. [读书笔记] R语言实战 (四) 基本数据管理

    1. 创建新的变量 mydata<-data.frame(x1=c(2,2,6,4),x2=c(3,4,2,8)) #方法一 mydata$sumx<-mydata$x1+mydata$x ...

  3. 挖一挖python中的深浅拷贝问题

    前几天在做面试题的时候,遇到一个与Python深浅拷贝的问题,今天总结出来一个方法,能够快速判断在对一个对象复制后,新对象与原来对象是否会互相影响的方法. 先抛出结论,然后我们对结论进行验证~~~ 先 ...

  4. visual studio 2017 使用码云gitee进行源代码管理

    在码云新建项目 复制项目地址 visual studio  操作 新建项目 提交到码云

  5. java内存管理之垃圾回收及JVM调优

    GC(garbage Collector 垃圾收集器)作用:a.内存的动态分配:b.垃圾回收注:Java所承诺的自动内存管理主要是针对对象内存的回收和对象内存的分配. 一.垃圾标记 程序计数器.Jav ...

  6. 我一不小心把ubuntu里的ps这样的命令删掉了,应该怎么重装呢

    sudo apt-get --reinstall install procps    

  7. POJ 3749

    第一道简单密码学的题,太水了,本不打算做,第一道,还是纪念一下. #include <iostream> #include <cstdio> #include <cstr ...

  8. Sublime Text 3 添加到右键菜单

    Sublime Text 3 添加到右键菜单 学习了:http://jingyan.baidu.com/article/cdddd41c99d07653ca00e147.html Windows Re ...

  9. 纯文本中识别URI地址并转换成HTML

    问题 有一段纯文本text, 欲将其插入DOM节点div中. text中可能有超链接, 邮件地址等. 假设有, 识别之. 分析 假设仅仅是纯文本, 插入div中, 仅仅要将div.innerText设 ...

  10. Test Precisely and Concretely

    Test Precisely and Concretely Kevlin Henney IT IS IMPORTANT TO TEST for the desired, essential behav ...