ACM八皇后详解

会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。
思路:
要求在8*8的方格中放置8个皇后。稍加分析知道,必定是每行放一个。
采用回溯算法。从第一行开始。依次遍历8列。检查该点是否可以放置皇后。如果可以放置,放置完成后,直接递归到下一行。继续以相同的方式检查。函数回溯的时候有两种情况。

  1. 由于前面错误的放法,导致本行没有可以放置的点。
  2. 八行已经全部放完。此时已经求出一个解。

上述两种情况都需要在回溯后,还原放置的点。
理由:

  1. 错误的放置导致的返回,所以这个点是错误的,不能放置,还原后继续试探本行的下一个点。
    2.八行已经放完时,还原这个点看看还有没有别的放法。

下面给出代码

int arr[8][8];

int sum = 0;

//每个点检查的八个方向
int dir[8][2] = {
    {-1, 0},
    {-1, 1},
    {0, 1},
    {1, 1},
    {1, 0},
    {1, -1},
    {0, -1},
    {-1, -1}
};

void PPmatrix(int *name, int H, int L);

int check(int x, int y);

void dfs(int xy, int num);


int main(int argc, char *argv[])
{
   
    dfs(0, 0);

    printf("sum = %d\n", sum);

    return 0;
}

void PPmatrix(int *name, int H, int L)
{
    int i = 0;
    int j = 0;

    for(i = 0; i < H; i++)
    {
        for(j = 0; j < L; j++)
        {
            printf("%d ", *(name++));
        }
        putchar('\n');
    }
    putchar('\n');
}


int check(int x, int y)
{
    int x1 = x, y1 = y;
    int i;

    for(i = 0; i < 8; i++)		//八个方向检查
    {
        x1 = x;
        y1 = y;
        while(x1 >= 0 && x1 < 8 && y1 >= 0 && y1 < 8)
        {
            if(arr[x1][y1] != 0)
                return 0;

            x1 += dir[i][0];
            y1 += dir[i][1];
        }
    }

    return 1;
}

void dfs(int xy, int num)
{
    int i;
    if(num >= 8)		//已经找到一中解法
    {
        PPmatrix(&arr[0][0], 8, 8);
        sum++;
        return;
    }

    for(i = 0; i < 8; i++)
    {
       int ch = check(xy, i);			//检查当前点是否可以放置
        if(ch == 1)
        {
            arr[xy][i] = 1;			//可以的话放置
            num++;
            
            dfs(xy+1, num);	//继续在下一行试探
            arr[xy][i] = 0;			//回溯,有两种情况,根据分析,两种情况都需要还原
            num--;					//还原,继续探索本行的下一个点
            
        }
    }

}

猜你喜欢

转载自blog.csdn.net/canhelove/article/details/83451107
今日推荐