八皇后問題

八皇后問題:在8*8的棋盤上放置8個(gè)皇后,保證任意兩個(gè)皇后之間不能相互攻擊。(即沒有兩個(gè)皇后是在同一行、同一類、或者同一對(duì)角線上)

  1. 計(jì)算出8皇后或者N皇后可能的所有擺放結(jié)果。其中8皇后共計(jì)有92種不同的解。
  2. 打印顯示出來(lái)其中的一種擺放結(jié)果或者所有的結(jié)果。

1. 回溯法:

回溯法:即試探法,系統(tǒng)的搜索所有解的方法。具體思想:從一條路往前走,能進(jìn)則進(jìn),不能進(jìn)則退出來(lái),換條路再走。解決八皇后問題的經(jīng)典算法。

偽代碼如下:

  1. 將棋盤存到一個(gè)N*N的矩陣中(8*8),二維數(shù)組。
  2. 算法開始,清空棋盤,當(dāng)前行設(shè)為第一行,當(dāng)前列設(shè)為第一列。
  3. 在當(dāng)前行當(dāng)前列的位置是否滿足條件:經(jīng)過這一點(diǎn)的行、列、以及兩條斜線上沒有其他皇后。若滿足:轉(zhuǎn)到步驟4;若不滿足,轉(zhuǎn)到步驟5。
  4. 滿足步驟3的條件:在當(dāng)前位置放置一個(gè)皇后,分以下情況:
  1. 若當(dāng)前行不是最后一行,當(dāng)前行設(shè)為下一行, 當(dāng)前列設(shè)為當(dāng)前行的第一個(gè)待測(cè)位置(不一定是第一個(gè)位置);轉(zhuǎn)到步驟3。
  2. 如果是最后一行,記錄下這個(gè)解。記錄之后,若當(dāng)前不是最后一列,當(dāng)前列設(shè)為下一列;若當(dāng)前列是最后一列,即最后一列,回溯,清空當(dāng)前行,然后當(dāng)前行設(shè)為上一行,當(dāng)前列設(shè)為當(dāng)前行的下一個(gè)待測(cè)位置。
  1. 不滿足步驟3的條件,分以下情況:
  1. 如果當(dāng)前列不是最后一列,當(dāng)前列設(shè)為下一列,繼續(xù)步驟3。
  2. 如果當(dāng)前列是最后一列,回溯,即,若當(dāng)前行已經(jīng)是第一行了,算法退出,否則,清空當(dāng)前行及以下各行的棋盤,然后,當(dāng)前行設(shè)為上一行,繼續(xù)步驟5。

算法改進(jìn):把棋盤存儲(chǔ)為一個(gè)二維數(shù)組,然后需要在第i行第j列放置皇后時(shí),根據(jù)問題的描述,首先判斷是在第i行是否有皇后,由于每行只有一個(gè)皇后,這個(gè)判斷也可以省略,然后判斷第j列是否有皇后,這個(gè)也很簡(jiǎn)單,最后需要判斷在同一斜線上是否有皇后,按照該方法需要判斷兩次,正對(duì)角線方向和負(fù)對(duì)角線方向。相對(duì)較為復(fù)雜。
若把棋盤存儲(chǔ)為一個(gè)N維數(shù)組q[N],數(shù)組中第i個(gè)元素的值代表第i行的皇后所在列的位置,這樣便可以把問題的空間規(guī)模壓縮為一維O(N),在判斷是否沖突時(shí)也很簡(jiǎn)單,首先每行只有一個(gè)皇后,且在數(shù)組中只占據(jù)一個(gè)元素的位置,行沖突就不存在了,其次是列沖突,判斷一下是否有a[i]與當(dāng)前要放置皇后的列j相等即可。至于斜線沖突,通過觀察可以發(fā)現(xiàn)所有在斜線上沖突的皇后的位置都有規(guī)律即它們所在的行列互減的絕對(duì)值相等,即| row – i | = | col – a[i] | 。這樣某個(gè)位置是否可以放置皇后的問題已經(jīng)解決。

1. 遞歸實(shí)現(xiàn)

代碼如下

//八皇后問題解法
public class Queen {
      static int count=0;  //統(tǒng)計(jì)解的個(gè)數(shù)
      static int N = 8;      //皇后個(gè)數(shù):8
      static int [] q = new int[N];  
//大小為8的數(shù)組:數(shù)組下標(biāo)表示:row,數(shù)組[i]對(duì)應(yīng)內(nèi)容:col。
      public static void print()
      {//打印解的坐標(biāo)位置及圖像
          for(int i=0;i<N;i++)
              System.out.println(i+" "+q[i]);
          for(int i=0;i<N;i++)
          {
              System.out.print("|");
              for(int j=0;j<N;j++)
              {
                  if(j==q[i])
                      System.out.print("Q|");
                  else
                      System.out.print(" |");
              }
              System.out.println();
          }
      }
      public static boolean canPlace(int i,int j)
      {//判斷坐標(biāo)(i,j)處是否可以放置皇后
          for(int k=0;k<i;k++)
          {
              if(q[k]==j||Math.abs(i-k)==Math.abs(j-q[k]))
                  return false;
          }
          return true;
      }
    public static void queen(int row)
    {//遞歸,從第row行開始循環(huán)每一列
        if(row==N)
        {
            count++;
            if(count==1)
            print();
        }
        else
        {
            for(int j=0;j<N;j++)
            {
                if(canPlace(row,j))
                {
                    q[row]=j;
                    queen(row+1);
                }
            }
        }
    }
  public static void main(String[] args) {
      for(int i=0;i<N;i++)  //初始化
      { q[i]=-1;}
      queen(0);
      System.out.println(count);
}
}
2. 非遞歸實(shí)現(xiàn)
public class Queen {
    static int N=8;
    static int[]q=new int[N];
    static int count=0;
     public static void print()
      {
          for(int i=0;i<N;i++)
              System.out.println(i+" "+q[i]);
          for(int i=0;i<N;i++)
          {
              System.out.print("|");
              for(int j=0;j<N;j++)
              {
                  if(j==q[i])
                      System.out.print("Q|");
                  else
                      System.out.print(" |");
              }
              System.out.println();
          }
      }
      public static boolean canPlace(int i,int j)
      {
          for(int k=0;k<i;k++)
          {
              if(q[k]==j||Math.abs(i-k)==Math.abs(j-q[k]))
                  return false;
          }
          return true;
      }
    public static void queen()
    { 
        int row=0,col=0;
        while(row<N)
        {
            while(col<N)
            {
                if(canPlace(row,col))
                {
                    q[row]=col;
                    col=0;
                    break;
                }
                else
                {
                    ++col;
                }
            }
            if(col==N)//q[row]==-1
            {
                if(row==0)
                    break;
                else
                {
                    --row;
                    col=q[row]+1;
                    q[row]=-1;  //把上一行皇后的位置清除,重新探測(cè)
                    continue;
                }
            }
            if(row==N-1)
            {
                count++;
                if(count==1)
                    print();
                col=q[row]+1;
                q[row]=-1;
                continue;
            }
            ++row;
        }
    }
  public static void main(String[] args) {
    for(int i=0;i<N;i++)//初始化
       q[i]=-1;
    queen();
    System.out.println(count);
}
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 八皇后問題問題描述:八皇后問題,是一個(gè)古老而著名的問題,是回溯算法的典型案例。該問題是國(guó)際西洋棋棋手馬克斯·貝瑟爾...
    藥藥耀耀閱讀 2,181評(píng)論 0 0
  • 問題描述: 八皇后問題,是一個(gè)古老而著名的問題,是回溯算法的典型案例:在8X8格的國(guó)際象棋棋盤上擺放八個(gè)皇后,使其...
    HeartGo閱讀 431評(píng)論 0 3
  • 問題描述 會(huì)下國(guó)際象棋的人都很清楚:皇后可以在橫、豎、斜線上不限步數(shù)地吃掉其他棋子。如何將8個(gè)皇后放在棋盤上(有8...
    指尖極光閱讀 1,072評(píng)論 0 0
  • 白殊晏:親愛的,又是一個(gè)愉快的周末,遠(yuǎn)在大洋彼岸的你正在干什么呢?最近忙著各種學(xué)校的事情,鑒于之前腦殘的一下子選了...
    Wonderland閱讀 244評(píng)論 0 1
  • ?這是奇小娜每天一篇原創(chuàng)文章的第31篇 一直把自己定義為“文藝女青年在創(chuàng)業(yè)”,聽起來(lái)挺別致的調(diào)調(diào),但是仔細(xì)一咂摸,...
    奇小娜閱讀 954評(píng)論 0 51

友情鏈接更多精彩內(nèi)容