您的位置:首页 > 编程语言 > Go语言

Algorlthm gosslp:八皇后问题浅谈

2012-07-25 20:09 225 查看
                                                                      八皇后

       8*8的棋盘上放八个皇后棋子,要求在纵行,竖行和斜行的八个方向上都不能有两个以上的皇后。1970和1971年,E.W.Dijkstra与N.Wirth曾用这个问题讲解程序设计技巧,淡然,像我这码农级程序员很难理解怎样应用到程序设计技巧中,现阶段只管理解问题的解决方法。

       八皇后问题主要使用递归求解,然而如何减少递归次数呢?

        在每次递归时,不必要所有的都检查过,例如若某列检查过,该列的其他格子就不在检查了,这个方法称为分支修剪。

        程序中风别在横竖八个地方和斜方向15个地方做了标记,若有皇后则递归返回。本人觉得斜方向的标记控制和递归的调用时问题的精华。

        C语言实现:

#include<stdio.h>
#include<stdlib.h>
#define N 8

int column[N+1];
int rup[2*N+1];
int lup[2*N+1];
int queen[N+1]={0};
int num;

void backtrack(int);

int main(void){
int i;
num = 0;
  	for(i=1;i<=N;i++)
		column[i] = 1;
for(i=1;i<=2*N;i++)
rup[i] = lup[i] =1;
backtrack(1);
return 0;
}

void showAnswer(){
int x,y;
printf("\n解答%d\n",++num);
for(y=1;y<=N;y++){
for(x=1;x<=N;x++){
if(queen[y]==x){
printf(" Q");
}else{
printf(" .");
}
}
printf("\n");
}
}

void backtrack(int i){
int j;

if(i>N){
showAnswer();
}else{
for(j= 1;j<=N;j++){
if(column[j] == 1&&lup[i-j+N] == 1){
queen[i] = j;
column[j] = rup[i+j] = lup[i-j+N] = 0;
backtrack(i+1);
column[j] = rup[i+j] = lup[i-j+N] = 1;
}
}
}
}




问题描述:

                                          
八皇后问题是大数学家高斯于1850年提出来的。该问题是在8×8的国际象棋棋盘上放置8个皇后,使得没有一个皇后能“吃掉”任何其他一个皇后,即没有任何两个皇后被放置在棋盘的同一行、同一列或同一斜线上。
                           

要求:

                             
编一个程序求出该问题的所有解。
                            

算法思想:

                            
回溯法
                            
使用回溯算法求解的问题特征,求解问题要分为若干步,且每一步都有几种可能的选择,而且往往在某个选择不成功时需要回头再试另外一种选择,如果到达求解目标则每一步的选择构成了问题的解,如果回头到第一步且没有新的选择则问题求解失败。

该问题也可扩展到N后问题求解,只需修改程序main函数中的n值即可。
                            

代码如下:

 


/************************************************************************


 *  n后问题求解


 ************************************************************************/




#include <stdio.h>


#include <stdlib.h>


#include <math.h>


#include <conio.h>




#define MAXNUMBER 20




//判断当前得到的解向量是否满足问题的解


bool place_queen(int x[],int k)


{


    int i;


    for(i=1;i<k;i++)


    {


        if((x[i]==x[k]) || (abs(x[i]-x[k])==abs(i-k)))


            return false;


    }




    return true;


}




//将结果简单信息打印到屏幕


void output_queens(int x[],int n)


{


    for(int i=1;i<=n;i++)


        printf("%3d",x[i]);




    printf("");


}




//将结果详细信息写入文件


void output_queens(FILE *fp,int number,int x[],int n)


{


    fprintf(fp,"solution %d:",number);


    for(int i=1;i<=n;i++)


    {


        for(int j=1;j<=n;j++)


        {


            if(j==x[i])


                fprintf(fp,"1  ");


            else


                fprintf(fp,"0  ");


        }


        fprintf(fp,"");


    }


    fprintf(fp,"");


}




/************************************************************************


 *  n后问题求解


 *  input  : n, the number of queens


 *  output : the vector of solution, X


 ************************************************************************/


int n_queens(FILE *fp,int n,int x[])


{


    int nCount=0;    //解个数


    int k=1;        //先处理第1个皇后


    x[1]=0;




    while(k>0)


    {


        x[k]=x[k]+1;//在当前列加1的位置开始搜索




        while(x[k]<=n && !place_queen(x,k))    //当前列位置是否满足条件


            x[k]=x[k]+1;    //不满足,继续搜索下一列位置




        if(x[k]<=n)    //若存在满足条件的列


        {


            if(k==n)//是最后一个皇后,则得到一个最终解


            {


                //break;    //此处若break,则只能得到一个解


                nCount++;


                output_queens(x,n);    //输出


                output_queens(fp,nCount,x,n);


            }


            else    //否则,处理下一个皇后,即第 k+1 个皇后


            {


                k++;


                x[k]=0;


            }


        }


        else        //若不存在满足条件的列,则回溯


        {


            x[k]=0;    //第k个皇后复位为0


            k--;    //回溯到前一个皇后


        }


    }




    return nCount;


}




int main()


{


    int n=8,x[MAXNUMBER]={0};




    FILE *fp=fopen("8皇后问题的解.txt","w");


    if(fp==NULL)


    {


        printf("can not wirte file!");


        exit(0);


    }




    printf("the queens are placed on the coloums :");


    //求解并写入文件


    int nCount=n_queens(fp,n,x);


    printf("there are %d solutions!",nCount);


    fclose(fp);


    getch();    




    return 0;


}

与其他方法对比:

 

#include <stdio.h>

#include <stdlib.h>

#define max 8

int queen[max], sum=0; /* max为棋盘最大坐标 */

void show() /* 输出所有皇后的坐标 */

{

    int i;

    printf("(");

    for(i = 0; i < max; i++)

    {

         printf(" %d", queen[i]);

    }

    printf(")\n");

    sum++;

}

 

int PLACE(int n) /* 检查当前列能否放置皇后 */

{

    int i;

    for(i = 0; i < n; i++) /* 检查横排和对角线上是否可以放置皇后 */

    {

        if(queen[i] == queen
|| abs(queen[i] - queen
) == (n - i))

        {

            return 1;

        }

    }

    return 0;

}

 

void NQUEENS(int n) /* 回溯尝试皇后位置,n为横坐标 */

{

    int i;

    for(i = 0; i < max; i++)

    {       

        queen
= i; /* 将皇后摆到当前循环到的位置 */

        if(!PLACE(n))

        {           

            if(n == max - 1)

            {

                show(); /* 如果全部摆好,则输出所有皇后的坐标 */

            }         

            else

            {

                NQUEENS(n + 1); /* 否则继续摆放下一个皇后 */

            }

        }

    }

}

 

int main()

{

    NQUEENS(0); /* 从横坐标为0开始依次尝试 */

    printf("%d", sum);

    system("pause");

    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: