java写的 n皇后程序
这学期人工智能有两个实验,n皇后和8数码的搜索算法实现,很多同学到网上找了程序就交了。但是我觉得这样做虽然省事,于与自己除了不丢学分之外,百害而无一利。作为学习编程这个专业的学生,我觉得解决问题的能力要有的,而且靠解决问题来提高自己的信心和兴趣是很重要的。很多同学由于不愿要煞费脑筋的去解决有难度的实验,结果造成快毕业了也不能入门,更不用提专业技能和热爱了。
上边这一段话,是鄙人的感受和如何对待学习的见解,一己之见。下面就把我的程序贴上来,也是自己研究课本之后按自己的想法做得,有没有什么重大的错误,还不知道。希望感兴趣的朋友,能针对算法,java的应用技巧,原则以及程序的不足提些意见。
(用Eclipse写的java控制台程序)
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
关键思路
首先,找到以下几个名词用程序怎么表示或者说表达:
规则(rules),不合法(dead), 路径(path),状态(state)
1.针对n皇后的问题,我将棋子的位置集合作为规则集合(rules)
2.路径同样是有先后顺序的位置的集合(实际上棋子怎么放,顺序不重要,但搜索要按一定的顺序进行)
3.某棋子不合法就是棋子能和已经加入到规则集合中的棋子互吃(kill)
4.实际上我将棋子简单的看成了点(看上去不像状态,但和课本上递归过程中的状态对应),具有x,y坐标,
这样就可给出棋子互吃的表达,进而可以验证是否合法。
另外递归过程,课本上已经给出了(《人工智能》马少平,朱小燕 编著),我就按这个过程,只是给出递归内部调用的具体方法的定义,然后依序调用
并用合适的结构存储集合和路径。
import
import java.util.*;
import java.lang.Exception;
SearchPath类
class SearchPath
public class SearchPath {
int nil = 0;
int fail = -1;
int num = 4;
int queenNum = num;
Solution<Queen> solution = new Solution<Queen>();
ArrayList<Solution<Queen>> solutions = new ArrayList<Solution<Queen>>();
/**
* construct a SearchPath instance with the number of lines and columns
*
* @param n
* number of queens
* @throws Exception
*/
public SearchPath(int n) throws NQueenException {
if (n < 4)
throw new NQueenException("numer is less than 4");
this.num = n;
}
/**
* construct a SearchPath instance with the number of lines and columns and
* number of queens.
*
* @param n
* number of rows and columns
* @param qnum
* number of queens
* @throws NQueenException
*/
public SearchPath(int n, int qnum) throws NQueenException {
if (n < 4)
throw new NQueenException("numer is less than 4");
if (qnum < 1)
throw new NQueenException("number of queens is too small");
this.num = n;
this.queenNum = qnum;
}
/**
* search path
*/
public void Search() {
//calculate time consumed
Calendar start, end;
start = Calendar.getInstance();
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
Queen q = new Queen(i, j);
// find the path
System.out.println("recurse "+q.toString());
//call backtrack
if (backTrack(q) == nil) {
//calculate time consumed
end = Calendar.getInstance();
long span = end.getTime().getTime()
- start.getTime().getTime();
System.out.println("Time used:" + span + " miliseconds");
// System.out.println(solution.size());
// add to one solution to solutions collection
solutions.add(solution);
solution = new Solution<Queen>();
}
}
}
}
/**
* print solutions
*/
public void printSolutions() {
System.out.println(solutions.size() + " solution(s):");
Iterator<Solution<Queen>> iter = solutions.iterator();
while (iter.hasNext()) {
printSolution(iter.next());
}
}
/**
* print one solution
*/
private void printSolution(Solution<Queen> sol) {
System.out.print("{");
Iterator<Queen> iter = sol.iterator();
while (iter.hasNext()) {
System.out.print(iter.next().toString() + " ");
}
System.out.print("}");
System.out.println();
}
/**
* recurse to search the path
*/
public int backTrack(Queen q) {
// add the position to result collection
solution.add(q);
//System.out.println("add one queen" + q.toString());
//find a path
if (hit(q)) {
System.out.println("nil" + q.toString());
return nil;
}
if (dead(q)) {
//remove queen already added to path
solution.remove(q);
System.out.println("dead" + q.toString());
return fail;
}
Queue<Queen> rules = calRules(q);
//loop to backtrack
while (rules != null && !rules.isEmpty()) {
Queen newq = (Queen) rules.poll();
if (backTrack(newq) == nil)
return nil;
}
// rules collection is empty and find no path
solution.remove(q);
System.out.println("empty" + q.toString());
return fail;
}
/**
* return true if get the path
*/
boolean hit(Queen q) {
if (solution.size() == queenNum && !dead(q))
return true;
else
return false;
}
/**
* verify whether q is invalid
*/
boolean dead(Queen q) {
Iterator<Queen> iter = solution.iterator();
Queen newq;
while (iter.hasNext()) {
newq = (Queen) iter.next();
if (kill(newq, q))
return true;
}
return false;
}
/**
* @param q
* queen get rules by the current position of queen
*/
Queue<Queen> calRules(Queen q) {
Queue<Queen> rules = new LinkedList<Queen>();
if (q.y + 1 < num) {
for (int i = 0; i < num; i++) {
for (int j = q.y + 1; j < num; j++) {
Queen newq = new Queen(i, j);
//
if (!kill(q, newq)) {
rules.offer(newq);
}
}
}
}
return rules;
}
/**
* Whether two queens can kill each other
*
* @param q1
* queen, q2 queen
* @return true can kill ;false can not kill
*/
public boolean kill(Queen q1, Queen q2) {
// no suicide
if (q1.x == q2.x && q1.y == q2.y)
return false;
// at the same line
if (q1.x == q2.x)
return true;
// in the same column
if (q1.y == q2.y)
return true;
// diagonal
if (Math.abs(q1.x - q2.x) == Math.abs(q1.y - q2.y))
return true;
return false;
}
}
Queen类,既是状态,也是棋子
class Queen
class Queen {
int x, y;
/**
*
* @param xposition
* x coordinate of this queen
* @param yposition
* y coordinate of this queen
*/
public Queen(int xposition, int yposition) {
this.x = xposition;
this.y = yposition;
}
/**
* print coordinate of this queen
*/
public String toString() {
return "(" + String.valueOf(this.x) + "," + String.valueOf(this.y)
+ ")";
}
}
Solution类,存放解决方案的集合,是对ArrayList的包装
class Solution
/**
* A simple wrapper of class ArrayList<E>. This is a generic class too. In order
* to used elegantly ,I wrap an ArrayList Instance inside of this class
*
* @author Sunmoonone
*/
class Solution<E> {
private ArrayList<E> arrayList = new ArrayList<E>();
/**
* returns an iterator over elements in the inner list in proper sequence.
*/
public Iterator<E> iterator() {
return this.arrayList.iterator();
}
/**
*
* @return size of ArrayList inside
*/
public int size() {
return this.arrayList.size();
}
/**
* Appends the specified element to the end of the list inside.
*
* @param o
* element to be appended to this list.
* @return <tt>true</tt> (as per the general contract of Collection.add).
*/
public boolean add(E o) {
if (this.arrayList.add(o))
return true;
else
return false;
}
/**
* Removes a single instance of the specified element from the inner list,
* if it is present (optional operation).
*
* @param o
* element to be removed from this list, if present.
* @return <tt>true</tt> if the list contained the specified element.
*/
public boolean remove(Object o) {
if (this.arrayList.remove(o))
return true;
else
return false;
}
}
NQueenException异常类,这个类没有必要写的
class NQueenException
/**
* The class <code>NQueenException</code> is a subclass that indicates
* conditions that a reasonable application might want to catch.
*
* @author Sunmoonone
*
*/
class NQueenException extends Exception {
/**
* generated serialVersionUID
*/
private static final long serialVersionUID = -304640658004618250L;
public NQueenException() {
super();
}
/**
* Constructs a new exception with the specified detail message. The cause
* is not initialized, and may subsequently be initialized by a call to
* {@link #initCause}.
*
* @param message
* the detail message. The detail message is saved for later
* retrieval by the {@link #getMessage()} method.
*/
public NQueenException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail message and cause.
* <p>
* Note that the detail message associated with <code>cause</code> is
* <i>not</i> automatically incorporated in this exception's detail message.
*
* @param message
* the detail message (which is saved for later retrieval by the
* {@link #getMessage()} method).
* @param cause
* the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public NQueenException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new exception with the specified cause and a detail message
* of <tt>(cause==null ? null : cause.toString())</tt> (which typically
* contains the class and detail message of <tt>cause</tt>). This
* constructor is useful for exceptions that are little more than wrappers
* for other throwables (for example,
* {@link java.security.PrivilegedActionException}).
*
* @param cause
* the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public NQueenException(Throwable cause) {
super(cause);
}
}
程序入口类Main,包含main函数,接受输入并调用搜索算法进行搜索,并打印结果。
public class Main {
/**
* @param args
*
*/
public static void main(String[] args) {
try {
SearchPath search = new SearchPath(readInt("rows and columns"),
readInt("queens"));
System.out.println("New SearchPath instance created.");
search.Search();
System.out.println("Search finished");
search.printSolutions();
System.out.println("All solutions have been printed");
} catch (NumberFormatException ex) {
System.out.println("You did not enter a valid Integer");
return;
} catch (IOException ex) {
System.out.println("IOException: " + ex);
return;
} catch (Exception ex) {
System.out.println(ex.getMessage());
return;
}
}
/**
* read an integer from console
*
* @return
*/
public static int readInt(String name) throws IOException {
String str = null;
System.out.println("Type in the number of " + name
+ " and hit <Enter>: ");
BufferedReader inStream = new BufferedReader(new InputStreamReader(
System.in));
str = inStream.readLine();
return Integer.parseInt(str);
}
}
class Main
public class Main {
/**
* @param args
*
*/
public static void main(String[] args) {
try {
SearchPath search = new SearchPath(readInt("rows and columns"),
readInt("queens"));
System.out.println("New SearchPath instance created.");
search.Search();
System.out.println("Search finished");
search.printSolutions();
System.out.println("All solutions have been printed");
} catch (NumberFormatException ex) {
System.out.println("You did not enter a valid Integer");
return;
} catch (IOException ex) {
System.out.println("IOException: " + ex);
return;
} catch (Exception ex) {
System.out.println(ex.getMessage());
return;
}
}
/**
* read an integer from console
*
* @return
*/
public static int readInt(String name) throws IOException {
String str = null;
System.out.println("Type in the number of " + name
+ " and hit <Enter>: ");
BufferedReader inStream = new BufferedReader(new InputStreamReader(
System.in));
str = inStream.readLine();
return Integer.parseInt(str);
}
}