Fork me on GitHub

八皇后的递归与非递归解

 

1、递归。递归真是个好东西,解法一目了然。

 

#include<stdio.h>
#define N 8

 

int l[14];
int r[14];
int q[N];
int col[N];
static int cnt = 0;

 

void try(int i)
{
int j;

 

for(j=0; j<N; j++)
{
if(l[i+j] == 0 && r[i-j+7] ==0 && col[j] == 0)
{
l[i+j]=1;
r[i-j+7] =1;
col[j] = 1;
q[i] = j;

 

    if(i+1 == N)
{
++cnt;
//    return;
}
else
{
try(i+1);
}

 

     l[i+j] = 0;
r[i-j+7] = 0;
col[j] = 0;
q[i] = -1;
}
}
}

 

int main()
{
int i;
for(i=0; i<14; i++)
{
l[i] = 0;
r[i] = 0;

 

}
for(i = 0; i<N; i++)
{
col[i] = 0;
q[i] = -1;
}
try(0);
printf("cnt = %d\n", cnt);
return 0;
}

 

 

 

2、非递归解

 

#include <iostream.h>
#define QUEEN 8 //皇后数量
int queen[QUEEN] ; //下标代表所在列号,值代表所在行号,
//如queen[1]=2表示第1列第2行有个皇后
bool col_YN[QUEEN] ;      //棋局的每一行是否有棋,有则为1,无为0 ;
bool passive_YN[2*QUEEN-1] ; //斜率为1的斜线方向上是否有棋,共有2*QUEEN-1个斜线
bool negative_YN[2*QUEEN-1] ; //斜率为负1的斜线方向上是否有棋
//用全局变量,因全局数组元素值自动为0
int main()

int col = 0 ;//游标,当前移动的棋子(以列计)
bool flag = false ;   //当前棋子位置是否合法
queen[0] = -1 ;      //第0列棋子准备,因一开始移动的就是第0列棋子
int count = 0 ;      //一共有多少种解法的计数器 ;

while(col>=0 ) //跳出条件是回溯到无法回溯时 
{
queen[col]++ ;      //col列上的皇后走到下一行试试
if(queen[col] >= QUEEN) //当前列全部走完

queen[col] = -1 ; //当前列棋子置于准备状态
col-- ;        //回溯到上一列的棋子
if(col>=0)      //回溯时要清理如下行,斜线的标志位   
{
col_YN[queen[col]] = false ; 
passive_YN[queen[col] + col] = false ;
negative_YN[QUEEN-1 + col - queen[col]] = false ;

}
else

//先判断棋子所在行没有棋子
if(col_YN[queen[col]] == false) 
{
flag = true ; 
//以下检查当前棋子是否与之前的棋子斜线相交
if( passive_YN[queen[col] + col] == true || negative_YN[QUEEN-1 + col -      queen[col]] == true) 
flag = false ;
else     
flag = true ;
if(flag) // flag为真表示位置合法

if(col == QUEEN-1) //列到达最后,即最后一个皇后也找到位置,输出解
{
count++ ; //解法的数目加一 ;
cout<<"***第"<<count<<"种解法***"<<endl ;
for(int i=0;i<QUEEN;i++)
cout<<"第"<<i<<"列皇后在第"<<queen[ i ]<<"行"<<endl;
}
col_YN[queen[col]] = true ;// 当前行设为有棋子
passive_YN[queen[col] + col] = true ;//当前行正斜率方向有棋子
negative_YN[QUEEN-1 + col - queen[col]] = true ; //当前行负斜率方向                   上也有棋子
col++ ;
if(col >= QUEEN) 
{ // 找到解后再次回溯找另外的解,这同上面无解回溯是一样的
col-- ;
col_YN[queen[col]] = false ; 
passive_YN[queen[col] + col] = false ;
negative_YN[QUEEN-1 + col - queen[col]] = false ;//原理同回溯
}      
flag = false ;     
}
}
}
}
cout<<QUEEN<<"皇后问题一共有"<<count<<"种解法"<<endl ;
return 0 ;
}

 

 

 

 

 

 

 

八皇后问题的实现(C语言)

 

2008-01-05 20:41

 

   八皇后问题主要靠回溯的方法实现, 与迷宫的实现相似, 但又困难了一些. 如迷宫的路径不因为上一步而改变, 八皇后的每一步都受约束于以前的步数, 并且, 迷宫只要找出一条路径就行,但八皇后则有很多的解法. 等等.

#include <stdio.h>

#define N 8           // 定义棋盘的格数, 通过改变,也可以是4皇后, 16皇后, 9皇后什么的.

int chess[N][N] = {0}; // 棋盘
int count = 0; // 有多少种放法

int canput(int row, int col) // 确定某一格能不能放
{
int i,j;
for(i = 0; i < N; i ++)
{
if(chess[i][col] == 1) //有 同列的
{
return 0;
}
for(j = 0; j < N; j++)
{
if(chess[row][j]==1) //有同行的
{
return 0;
}
if(((i-row)==(j-col)||(i-row)==(col-j))&&chess[i][j]==1) // 对角线上有的
{
return 0;
}
}
}
return 1;
}

void print_chess() // 打印放置的方案
{
int i, j;
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
printf("%d ", chess[i][j]);
}
printf("\n");
}
printf("\n");
}

int put(int row)     // 放置棋子, row是从哪一行开始, 通常是0
{
int j, s;
for(j = 0; j < N; j++) // 此一行的每一个格子都要试试能不能放
{
if(canput(row, j)) // 假如这格能放的话
{
chess[row][j] = 1; // 放置

    if(row == N-1) // 已经到了最后一行, 那么肯定成功******************************************************
{
count = count +1;

    print_chess();
chess[row][j] = 0; //成功后, 寻找下一种方法
continue;
}
s = put(row+1); // 放置下一行的
if(s == 0)    // 假如下一行不能放
{
chess[row][j] = 0; // 那么这格是放错了的, 清除
continue;           // 找本行的下一个方格
}
else
{
break;
}   
}
}
if(j==N)    // 如果这一行的每个空格都不能放置
{
return 0; // 那么本行放置失败
}
else
{
return 1; // 本行放置成功
}
}

int main()
{
int s ;

s = put(0); // 放置
printf("the number of put way is %d\n", count); //打印信息

return 0;
}

     这个程序有个奇怪的地方, 就是在有星号的那一行, 当把chess[row][j] = 0, continue;两句去掉时,发现程序依然能正常运行. 原因就是: 当行比列多时, 假如皇后是的数目是列那么多, 是肯定放不成功的, 所以, 当程序要在最后一行的下一行放皇后时,怎么放也不成功,所以, 程序会不断调整以前的方法,但打印信息却在这里执行, 所以能打出正确信息. 但不建议去掉, 因为操作未知内存终究不是件好事.

 

posted on 2012-05-24 11:07  pengyingh  阅读(550)  评论(0)    收藏  举报

导航