ckook

导航

 

问题:将8颗棋子放入一个8行8列的棋盘中,要求每颗棋子所在的行、列以及正斜线上不能有其它棋子。将所有可能的棋局输出。

  显见每行且每列只能放置一颗棋子,才能满足每颗棋子所在的行、列不能有其它棋子。那么,假设去除正斜线上不能有多颗棋子这一限制条件,原问题就转化为8个元素全排列的问题。

  于是我们得到了解决方案,生成所有8! 种排列并去除那些斜线上有多颗棋子的排列。这样就要生成 8! 种排列,不但计算量大,而且其中绝大部分不满足同一斜线上不能有多颗棋子这一条件。那么有没有优化的办法?

  有!——那就是回溯(试错):递归的生成排列,在生成的过程中,一旦产生不满足斜线限制条件的排列则不再继续深入其子排列问题(即剪支),而是选择下一个符合的排列继续试错下去。

代码如下:

 

#include <stdio.h>
#define N 8

int S[N] = {0,1,2,3,4,5,6,7};

/*限制条件*/
bool constraint(int end)
{
    for(int i = 0; i <= end; i++)
        for(int j = i+1; j <= end; j++)
            if(i - j == S[i] - S[j] || j - i == S[i] - S[j]) /*在同一斜线上*/
                return false;
    return true;
}

/*交换两数*/
void swap(int *a, int *b)
{
    int t = *a;
    *a = *b;
    *b = t;
}

/*输出八皇后问题的解*/
void dump(int n)
{
    for(int i=0; i<N; i++)
        printf("%dth : (%d, %d) ,", n, i, S[i]);
    printf("\n");
}

/*递归的生成排列*/
void queen8(int s)
{
    if(s > N-1) {
        static int nc = 0; /*计数*/
        dump(++nc); /*输出*/
        return;
    }
    
    for(int i=s; i<N; i++) {
        swap(&S[s], &S[i]);
        if(constraint(s)) queen8(s + 1); /*若满足限制条件,继续递归子问题*/
        swap(&S[s], &S[i]);
    }
}

/*主程序*/
int main()
{
    queen8(0);
}

 

 

posted on 2012-05-29 20:26  ckook  阅读(372)  评论(0)    收藏  举报