
1 /**********************************************************************************
2 *Name: N皇后问题
3 *Date: 2022.01.17
4 *Author: 吕辉
5 *Description: N皇后问题要求在一个 N * N 格的棋盘上放置N个皇后,使其互不攻击。
6 * 按规则互不攻击的约束条件为,任意两个皇后不能处于同一行、同一列或同一对角线上,
7 * 现要求给出满足约束条件的所有棋盘布局。
8 ***********************************************************************************/
9 #define _CRT_SECURE_NO_WARNINGS
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <math.h>
13 #include <time.h>
14
15 /*孩子兄弟表示法的抽象数据类型*/
16 typedef struct node
17 {
18 int data;/*存储皇后的横坐标*/
19 struct node* fristchild;
20 struct node* nextsibling;
21 struct node* parent;
22 }Node, *Tree;
23
24 void Print(Tree A, int n);
25 int Place(Tree A, int layer);
26 void Queen(Tree* A, int layer, int n, int* sum);
27
28 int main(void)
29 {
30 int n = 0;
31 int sum = 0;
32 clock_t start;
33 clock_t finish;
34 Tree A = NULL;
35
36 printf("请输入棋盘阶数:");
37 scanf("%d", &n);
38
39 start = clock();
40 Queen(&A, 1, n, &sum);
41 finish = clock();
42 printf("%d阶棋盘共有%d种布局,用时%.fms\n", n, sum, (double)(finish - start));
43 system("pause");
44 return 0;
45 }
46
47 /**********************************************
48 * Function: Print
49 * Description: 打印符合约束条件的棋盘布局
50 * Called By: Queue
51 * Parameter : A 树的结点指针
52 * n 所在层数
53 ***********************************************/
54 void Print(Tree A, int n)
55 {
56 while (A)
57 {
58 printf("(%d,%d) ", n--, A->data);
59 A = A->parent;
60 }
61 printf("\n");
62 }
63
64 /***************************************************
65 * Function: Place
66 * Description: 判断当前皇后位置是否符合约束条件
67 * Called By: Queue
68 * Parameter : A 树的结点指针
69 * layer 当前结点所在层数
70 * Return: 返回 0 表示当前皇后位置不符合约束条件
71 * 返回 1 表示当前皇后位置符合约束条件
72 ****************************************************/
73 int Place(Tree A, int layer)
74 {
75 int prelayer = layer;/*前一行皇后所在行号*/
76 int data = A->data;/*当前行皇后所在列号*/
77 A = A->parent;
78 while (A)
79 {
80 prelayer--;
81 /*皇后位置在同一列或者在同一对角线上返回0*/
82 if (A->data == data || (abs(prelayer - layer) == abs(A->data - data)))
83 {
84 return 0;
85 }
86 A = A->parent;
87 }
88 return 1;
89 }
90
91 /********************************************************
92 * Function: Queen
93 * Description: 通过回溯法查找所有可能组合并打印
94 * Called By: main
95 * Parameter : A 树的结点指针
96 * layer 当前结点所在层
97 * n 所在层数
98 * sum 可能的组合总数
99 *********************************************************/
100 void Queen(Tree* A, int layer, int n, int* sum)
101 {
102 int i = 0;
103 Tree P = NULL;
104 Tree Pre = NULL;
105 if (layer > n)
106 {
107 Print((*A), n);
108 (*sum)++;
109 }
110 else
111 {
112 for (i = 1; i <= n; i++)
113 {
114 P = (Tree)calloc(1, sizeof(Node));
115 P->data = i;
116 if ((*A))
117 {
118 if ((*A)->fristchild == NULL)
119 {
120 (*A)->fristchild = P;
121 }
122 P->parent = (*A);
123 }
124 else
125 {
126 P->parent = NULL;
127 }
128
129 if (Place(P, layer) == 1)
130 {
131 Queen(&P, layer + 1, n, &(*sum));
132 }
133 if (Pre)
134 {
135 Pre->nextsibling = P;
136 }
137 Pre = P;
138 }/*for循环*/
139 }/*else*/
140 }