n皇后问题(人工智能试验java实现)

      今天,上午看了个电影<证人>.-----世界真奇妙,平常的一次撞车,把几个人拉到了一块!.,看的时候,室友说'谢霆锋和<越狱>中m一样流鼻血..呵呵..感觉谢与米勒差远啦,总给人种感觉很轻浮,好像小孩耍帅一样.晕--....然后和同学一块买了套内衣,洗洗澡,下午上课啦,老师划重点,下个星期就考试啦...哦,还有一买东西就被同学'骂'...笨,嘴笨,不会搞价,太幼稚总觉得价钱不会差太远,其实老板太黑啦-----
       晚上随便看了些网页,,又把前几天<人工智能>的一个试验题目拿出来,完善了些...(*^__^*) 嘻嘻……,以前没写过技术博客,很差劲,,,,绞尽脑汁忙乎半天,想出的答案,网上一搜,一大堆,答案,还比自己的要好,,并且有些都已经是7,8年前的啦,,,服啦..
      不过.....哎,,啥也不说啦..,尽量写下去吧-----孤芳自赏也好,再者,总还有后来者呵1
把皇后问题:
       设在初始状态下在国际象棋上没有任何棋子。然后顺序在第 1 行,第 2 行,…,第 n 行上布放棋子。在每一行中有 n 个可选择位置,但在任一时刻,棋盘的合法布局都必须满足 3 个限制条件:即任何两个棋子不得放在棋盘上的同一行、或者同一列、或者同一斜线上。试编写一个算法(递归或者非递归均可),求解并输出此问题的所有合法布局。
 
首先用非递归实现吧:
1..把棋盘看成一个二维坐标,创建一个Queen类.表示皇后,而每个皇后有一个Point型变量,唯一确定皇后在二维坐标中的位置..且有一个isControl方法,判断是否冲突!
2..解决该问题,用NQueen类,四个变量,含义参考愿程序,主要方法findAndShowAllResults()查找并显示所有解,printResult()getQueen(int index)
3..主要思路:先把第一个皇后放在(0,0)坐标,...
         然后getQueen(index)找到一个queenTemp与之前皇后(0-index位置的皇后)都不冲突的位置..
-----------if(不为空)表示找到了,则赋值queenStack[index]queenTemp,同时index+1继续找下一个,止到index+1等于总皇后数;
------------else 为空,表示queeTemp不存在,即表示第index+1个皇后无处安放,则尝试:::把第index个皇后位置后移到下一个合法的位置,重新查找getQueen(index),     
      :::若后移不可行,则移动第index-1个皇后,一次类推...
4..getQueen(index)//for循环顺次判断坐标(index,y)[y from 0 to queenCount-1]处与index以前的皇后是否冲突...冲突则break跳出for循环尝试(index,y+1)位置....不冲突则完成....若当y=queenCount-1时仍冲突则返回null
代码如下::
import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
    

/**
* @author    Sunpander
* @version 2008-12-10
*/
public class NQueen {

  Queen queenStack[]    = new Queen[8]; //存放皇后的数组
   int     queenCounts = 0;                         //皇后总数
   int     queenIndex = 0;                             //正测试的皇后位置
   int     resultCount = 0;                         //解的个数.
   public NQueen(){
    queenCounts = 8;
    queenStack = new Queen[queenCounts];
  }
   public NQueen( int num)
  {
     this.queenCounts = num;
    queenStack = new Queen[queenCounts];
  }
   /**
    * 在控制台显示结果
    */
   public void printResult()
  {
     if(queenIndex < =0 || resultCount==0)
      System.out.println( "无解");
     else
    {
      System.out.println( "第"+resultCount+ "种解法begin:");
       for( int k =0;k<queenCount;k++)
      {
        
        System.out.println( "第 "+(k+1)+ " 个皇后位置:"+queenStack[k]);
      }
      System.out.println( "end.");
    }
  }
   /**查找并显示所有解,
    *    
    */
   public void findAndShowAllResults()
  {
     int  resultCount =0;
     int start = 0;
     while(start<=queenCounts-1)
    {    
      queenIndex = 0;
      Point point = new Point(0,start); //第一个皇后的位置设置为(k,0);
      queenStack[queenIndex] = new Queen(point);
      queenIndex ++;
       while(queenIndex >=0 && queenIndex <=queenCounts-1)
      {
        Queen queenTemp;
        queenTemp = getQueen(queenIndex);
         //queenTemp为null表示上一个queen(即queenIndex--处)的位置导致剩余的queen无法放置
         //尝试把queenStack[(--queenIndex)]的y+1;
         if( null==queenTemp)
        {
           boolean flag = true;
           while(flag)
          {
            queenIndex --;
             if(queenIndex < 0)
               break;
             if(queenStack[queenIndex].pos.y == queenCounts-1)
            {} //queenStack[(--queenIndex)]的y已经无法在加了,则继续向前看
             else
            {
              queenStack[queenIndex].pos.y++;
              queenIndex++;
              flag = false;
              Point pot = queenStack[queenIndex-1].pos;
               for( int index=0;index<queenIndex-1;index++)
              {
                 if(queenStack[index].isControl(pot))
                {
                  flag = true;
                   break;
                }
              }
            }
          }
        }
         else
        {
          queenStack[queenIndex++]=queenTemp;
            
        }
      }
       if(queenIndex>0)
      {
        System.out.println( "第"+(++resultCount)+ "种解法:");
         this.printResult();
        start = queenStack[0].pos.y+1;
      }

       else
        start++;
    }
     /**
     * 此处08-12-11-16:44-sunpander作修改;:
     *                        没考虑无解的情况,添加if部分;
    
     */
     if(queenIndex < 0 && (resultCount<=0))
    {
      System.out.println( "无解");
    }
  }
   /**
    *    
    * @param index
    * @return Queen(new Point(index,y))或者null(null表示此路不通)
    */
   public Queen getQueen( int index)
  {
     int x=0,y=0;
     boolean isNotOver = true;
     while(isNotOver)
    {
      isNotOver = false;
       for( int k=0;k<index;k++)
      {
         //判断坐标(index,y)处是否冲突.冲突则break跳出for循环尝试(index,y+1)位置
         if(queenStack[k].isControl( new Point(index,y)))
        {
          isNotOver = true;
           break;
        }
      }
       if(y<=queenCounts-1 && isNotOver)
      {
        y++;
      }
       if(y>=queenCounts)
      {
         return null;
      }
    }
     //不冲突则,返回(index,y)处皇后
     return new Queen( new Point(index,y));
  }
   /**
    * @param args
    * @throws IOException    
    */
   public static void main(String[] args) throws IOException {
     // TODO Auto-generated method stub
//若只要求输出一个结果..则可直接把第一个皇后固定在(0,0)一次循环就好!;
     while( true)
    {
       int num = 8;
      BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
      System.out.println( "输入皇后数");
       boolean isWrongInput = true;
       /**
        * 此处08-12-11-16:44-sunpander作修改;:
        *             以前没考虑当输入不合法的情况;
        *                  if(str!=null && str!="\r\n")
        *                                num = Integer.parseInt(str);
        *                            else
        *                                 System.out.println("输入数字");
        */
       while(isWrongInput)
      {
       try {
            String str =    br.readLine();
          num = Integer.parseInt(str);    
         } catch (NumberFormatException e) {
        System.out.println( "请输入数字(");
        isWrongInput = true;
         continue;
      }
      isWrongInput = false;
      }
      NQueen nq = new NQueen(num);
        nq.findResult();
        nq.printResult();
       //nq.findAndShowAllResults();
    }
  }

}
/*
*每个皇后为一个类.类有一个变量Point,x表示行,y表示列.pos指定皇后位置.
* 一个isControl方法判断是给定点与皇后位置是否冲突,
*/
   class Queen {
    Point pos;
    
     public Queen() {
        pos = new Point();
    }
     public Queen(Point pos) {
         this.pos = pos;
    }
     /**
     * 判断是给定点与皇后位置是否冲突,需满足即不在同一直线,也不在同一竖线,且不在同一斜线上则不冲突
     * 也即看参数Point的x,y与本类对象的point变量的x1,y1满足(x!=x1,y!=y1,x-x1!=y-y1,x+y!=x1+y1
     * 都满足则不冲突返回false(即指定的点可以再放皇后!
     * @param point
     * @return isControl
     */
     public boolean isControl(Point point) {
       boolean isControl = true;
             if (point.x != pos.x
                 && point.y != pos.y
                 && Math.abs(point.x - pos.x) != Math.abs(point.y - pos.y)
                 && Math.abs(point.x + point.y) != Math.abs(pos.x + pos.y))    
            {
                            isControl = false;
            }
             return isControl;
    }
     public String toString(){
       return ( "第"+(pos.x+1)+ "行"+ "第"+(pos.y+1)+ "列");
    }
  }
该程序遇到的问题(已解决的):
1,用输入数字时,要考虑转换不合法,或为负等
2.main()方法添加while(isDebug){}用于多次输入判断
3.重写toString()可以直接返回该类表示的意义!
4.开始想简单地用for循环从(0,0)到(0,queenCount-1)执行queenCount-1次,发现,结果可能出现重复.后改正(见程序)
 
用递归实现 (递归,呵呵,若明白含义,非常简单)
1..首先引用高人的想法,直接用int[]...数组的下标+1表示行数,而该下标的值则表示列数..... 
2..主要函数  queen(int nowIndex)
-----------if(nowIndex == queenCount)表示nowIndex之前的皇后已经放好,则直接输出结果
-----------else    for循环试探index(index从1到queenCount)处的queen能否放在地index处,,能即isControl(nowIndex)==false不冲突,则递归queen(index+1)
3...isControl(index)见程序注释
源代码如下:
    

public class NqueenDigui
{
   int            queenCount; //皇后数
   int            resultCount; //解的个数
   int[]    queenSite = new int[32];
    
   public static void main(String agrs[])
  {
    
    NqueenDigui nqueen = new NqueenDigui();
    nqueen.queenCount = 4;
    nqueen.queen(0);
  }
/*
    * 判断是否冲突,如果数组queenSite,有相等的值或者有2值的差等于下标差,则返回true即冲突,
    * 否则返回false.表示不冲突,该位置可以放置皇后!
    * ...sunpander...08-12-15
*/
   public boolean isControl( int n) {    
     for( int index=0;index<n;index++)
    {
       if ((Math.abs(queenSite[n]-queenSite[index]) == Math.abs(n-index))
          ||( queenSite[n]== queenSite[index]))
         return true;
    }
         return     false;
  }
   public void printResult1()
  {
     for( int j=0 ;j<queenCount;++j)
    {
      System.out.println( "queen["+(j+1)+ "]"+ "="+queenSite[j]);
    }
  }
   /**
    * 在控制台显示结果
    */
   public void printResult()
  {
     if(queenCount <= 0)
      System.out.println( "无解");
     else
    {
      System.out.println( "第"+resultCount+ "种解法begin:");
       for( int k =0;k<queenCount;k++)
      {
        System.out.println( "第 "+(k+1)+ " 个皇后位置:"+ "第"+(k+1)+ "行"+ "第"+queenSite[k]+ "列");
      }
      System.out.println( "end.");
    }
  }
   /*
    * 主要函数,从0开始,即把第一个皇后放在第一列!
    *        然后把二个放在第一列,如果不冲突,则放置第三个皇后.冲突则放第二列
    *                则放置第三个皇后,冲突则放着第二列,再检查是否冲突
    *              ......
    *                    如果第n个皇后放置在第n列,仍然冲突,则向上一个皇后返回,放着上一个皇后在它的下一列
    */
   public void queen( int nowIndex)
  {
     if(nowIndex == queenCount)
    {
      printResult();
    }
     for( int index = 1;index<=queenCount;index++)
    {
      queenSite[nowIndex] = index;
       if(!isControl(nowIndex))
              queen(nowIndex+1);
    }    
    
  }
}

 哎,把代码加到附件,感觉看着不是很方便,,就仍旧粘贴啦,,有点长啦--就这吧,其实都共同学习,,,也不是自己单独得到的答案,所以...if(你路过&&看过)请不啬指教,多多提意见;else 期待你的关注!;;
啊!!!!完工了,呵呵````哦!!说起递归不得不说汉诺塔(用递归很简单,非递归则麻烦)......

你可能感兴趣的:(java基础,人工智能,八皇后,N皇后,回溯算法)