八皇后问题

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


     在程序设计中还有一种方法叫做"回溯法".他不是按照某种公式或确定的法则,求问题的解,而是通过试探和纠正错误的策略,找到问题的街.这种方法一般是从一个原始状态出发,通过若干步试探,最后达到目标状态终止.
    回溯法在理论上来说,就是在一棵搜索树中从根结点出发,找到一条达到满足某条件的子结点的路径.在搜索过程中,对于每一个中间结点,他的位置以及向下搜索过程是相似的,因此完全可以用递归来处理.典型的例子就是著名的"八皇后问题".
    "八皇后问题"是在国际象棋棋盘上放置八个皇后,使她们不能相吃.国际象棋中的皇后可以吃掉与她处于同一行,同一列,同一对角线上的棋子.因此每一行只能摆放一个皇后.因共有八行,所以每行有且只有一个皇后.
    在本例中皇后的位置有一个一维数组来存放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();  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值