posts - 21,  comments - 9,  trackbacks - 0

回溯法:八皇后问题,一个经典问题

     在程序设计中还有一种方法叫做"回溯法".他不是按照某种公式或确定的法则,求问题的解,而是通过试探和纠正错误的策略,找到问题的街.这种方法一般是从一个原始状态出发,通过若干步试探,最后达到目标状态终止.
    回溯法在理论上来说,就是在一棵搜索树中从根结点出发,找到一条达到满足某条件的子结点的路径.在搜索过程中,对于每一个中间结点,他的位置以及向下搜索过程是相似的,因此完全可以用递归来处理.典型的例子就是著名的"八皇后问题".
    "八皇后问题"是在国际象棋棋盘上放置八个皇后,使她们不能相吃.国际象棋中的皇后可以吃掉与她处于同一行,同一列,同一对角线上的棋子.因此每一行只能摆放一个皇后.因共有八行,所以每行有且只有一个皇后.
    在本例中皇后的位置有一个一维数组来存放A(I)=J表示第I行皇后放在第J列.下面主要来看看怎么样判断皇后是否安全的问题.(1)首先,用一维数组来表示,已经解决了不在同一行的问题.(2)对于列可以引进一个标志数组C[J],若J列上已放了皇后,则C[J]=FALSE.(3)对于左上右下的对角线I-J为一常量,位于[-7,+7]之间,再此引入标志数组L[-7..7];对于左下右上的对角线,类似的有I+J等于常量,用数组R[2..16]来表示.当在第I行,第J列上放置了皇后,则只需设置:C[J]:=FALSE; L[I-J]:=FLASE; R[I+J]:=FALSE就可以解决皇后的安全问题了.

 

问题描述:在标准国际象棋的棋盘上(8*8格)准备放置8只皇后,我们知道,国际象棋中皇后的威力是最大的,她既可以横走竖走,还可以斜着走,遇到挡在她前进路线上的敌人,她就可以吃掉对手。要求在棋盘上安放8只皇后,使她们彼此互相都不能吃到对方,求皇后的放法。
/************************************************************************/
/*                                   */
/*    问题:在8×8的国际象棋棋盘上放置8个皇后,要求任意两个皇后       */
/*       不能在同一行、同一列或同一条对角线上。             */
/*                                   */
/*    本程序使用递归-回溯法求解8皇后问题。Visual C++ 6.0 调试通过。  */
/*    作者 晨星     2002年5月9日                   */
/*                                   */
/************************************************************************/
#include <stdio.h>
#include <conio.h>
#include <math.h>
#define QUEENS 8
//!记录解的序号的全局变量。
int iCount = 0;
//!记录皇后在各列上的放置位置的全局数组。
int Site[QUEENS];
//!递归求解的函数。
void Queen(int n);
//!输出一个解。
void Output();
//!判断第n个皇后放上去之后,是否有冲突。
int IsValid(int n);
/*----------------------------Main:主函数。 ----------------------------*/
void main()
{
     //!从第0列开始递归试探。
     Queen(0);
     //!按任意键返回。
     getch();
}
/*-----------------Queen:递归放置第n个皇后,程序的核心!----------------*/
void Queen(int n)
{
     int i;
     //!参数n从0开始,等于8时便试出了一个解,将它输出并回溯。
     if(n == QUEENS)
     {
           Output();
           return;
     }
      
     //!n还没到8,在第n列的各个行上依次试探。
     for(i = 1 ; i <= QUEENS ; i++)
     {
           //!在该列的第i行上放置皇后。
           Site[n] = i;
           //!如果放置没有冲突,就开始下一列的试探。
           if(IsValid(n))
                 Queen(n + 1);
     }
}
/*------IsValid:判断第n个皇后放上去之后,是否合法,即是否无冲突。------*/
int IsValid(int n)
{
     int i;
     //!将第n个皇后的位置依次于前面n-1个皇后的位置比较。
     for(i = 0 ; i < n ; i++)
     {
           //!两个皇后在同一行上,返回0。
           if(Site[i] == Site[n])
                 return 0;
           //!两个皇后在同一对角线上,返回0。
           if(abs(Site[i] - Site[n]) == (n - i))
                 return 0;
     }
     //!没有冲突,返回1。
     return 1;
}
/*------------Output:输出一个解,即一种没有冲突的放置方案。------------*/
void Output()
{
     int i;
     //!输出序号。
     printf("No.%-5d" , ++iCount);
     //!依次输出各个列上的皇后的位置,即所在的行数。
     for(i = 0 ; i < QUEENS ; i++)
           printf("%d " , Site[i]);
     printf("n");
}


STL源代码
用了STL, 方法是一样的.
#include <iostream>
#include <string>
using namespace std;
void queen(const string t, const string s)
{
    if (s=="") cout<<t<<endl;
    else
        for (int i=0; i<s.length(); i++) {
            bool safe=true;
            for (int j=0;j<t.length();j++) {
                if (t.length()-j==abs(s[i]-t[j])) safe=false;
            }
            if (safe) queen(t+s[i], s.substr(0,i)+s.substr(i+1));
    }
}
int main()
{
            string s="01234567";
    queen("",s);
    system("PAUSE");
    exit(EXIT_SUCCESS);
}

递归解八皇后问题
/*递归法解八皇后问题*/
/*作者黄国瑜,《数据结构(C语言版)》清华大学出版社*/
char Chessboard[8][8]; /*声明8*8的空白棋盘*/
int N_Queens(int LocX, int LocY, int Queens) /*递归*/
{
int i,j;
int Result=0;
if(Queens == 8)/*递归结束条件*/
   return 1;
else if(QueenPlace(LocX,LocY))/*递归执行部分*/
  {
  Chessboard[LocX][LocY] = 'Q';
  for(i=0;i<8;i++)
    for(j=0;j<8;j++)
    {
    Result += N_Queens(i,j,Queens+1);
    if(Result>0)
      break;
    }
  if(Result>0)
    return 1;
  else
    {
    Chessboard[LocX][LocY] = 'X';
    }
  }
else
  return 0;
}
int QueenPlace(int LocX,int LocY) /*判断传入坐标本身及入八个方向上是否有皇后*/
{
int i,j;
if(Chessboard[LocX][LocY] != 'X')
  return 0;
for(j=LocY-1;j>=0;j--)
  if(Chessboard[LocX][j] != 'X')
    return 0;
for(j=LocY+1;j<8;j++)
  if(Chessboard[LocX][j] != 'X')
    return 0;
for(i=LocX-1;i>=0;i--)
  if(Chessboard[i][LocY] != 'X')
    return 0;
for(i=LocX+1;i<8;i++)
  if(Chessboard[i][LocY] != 'X')
    return 0;
i= LocX - 1;
j= LocY - 1;
while (i>=0&&j>=0)
  if(Chessboard[i--][j--] != 'X')
    return 0;
i= LocX + 1;
j= LocY - 1;
while (i<8&&j>=0)
  if(Chessboard[i++][j--] != 'X')
    return 0;
i= LocX - 1;
j= LocY + 1;
while (i>=0&&j<8)
  if(Chessboard[i--][j++] != 'X')
    return 0;
i= LocX + 1;
j= LocY + 1;
while (i<8&&j<8)
  if(Chessboard[i++][j--] != 'X')
    return 0;
return 1;
}
main() /*主程序*/
{
int i,j;
for(i=0;i<8;i++)
  for(j=0;j<8;j++)
    Chessboard[i][j] = 'X';
N_Queens(0,0,0);
printf("the graph of 8 Queens on the Chessboard.is:n");
for(i=0;i<8;i++)
  for(j=0;j<8;j++)
  {
  if(Chessboard[i][j] == 'Q')
    printf("(%d,%d)n",i,j);
  }
getch();
}
/*********************************************************
*****************八皇后问题*******************************
************根据严书给的类c算法求得************************
*********************************************************/
#include<stdio.h>
#define N 8
int col=1,row=1,slash=1,bslash=1;
int a[N][N];
int p,q,k,l;
int num=0;
void trial(int i)
{
int j;   /*注 意,这里的j 一定要设为内部变量*/
if(i==N)
{
num++;
for(k=0;k<N;k++)
{
for(l=0;l<N;l++)
{
  if(a[k][l]==1)
   printf("@");
  else printf("*");
}
printf("n");
}
printf("nn");
getchar();
}
else
{
for(j=0;j<N;j++)
{
for(k=0;k<i;k++)
  if(a[k][j]==1)
  {
   col=0;
   break;
  }     /*列*/
p=i-1;
q=j+1;
while((p>=0)&&(q<N))
{
  if(a[p][q]==1)
  {
   slash=0;
   break;
  }
  p--;
  q++;
}
p=i-1;
q=j-1; /*对角*/
while((p>=0)&&(q>=0))
{
  if(a[p][q]==1)
  {
   bslash=0;
   break;
  }
  p--;
  q--;
}      /*斜对角*/
if((col==1)&&(slash==1)&&(bslash==1)) /*条件判断*/
{
  a[i][j]=1;
  trial(i+1);
}
col=1;slash=1;bslash=1;
a[i][j]=0;
}
}
}
void main()
{
trial(0);
printf("%dn",num);
getchar();
}

posted on 2010-08-20 18:34 崔佳星 阅读(853) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(1)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜