问题分析考虑八皇后问题,最简单的方法就是对棋盘的每个格子进行有或没有的判断。得到的问题规模就是O(2^(n*n)),也就是2的64次方。指数增长的时间复杂度是非常可怕的,不推荐这种做法,但是考虑不同人对问题的思考,下面将会摆出暴力解N皇后的解法。下面给出的各种解法都采用了空间换时间的方式,设置一个数组a,数组下标表示的哪一行,数组的值表示的是哪一列。
(1)暴力解:对n = 8的问题来说,皇后所在的行为0 ~ 7。因此,8个皇后可能存储位置在00000000~77777777共8^8种情况。基于暴力分析的时候,该问题可以看作是8的8进制数字。基于该思想的代码如下。
#include
#include
#define n 8
int place(int a[n])
{
int i, j;
for(i = 0; i < n; i++)
for (j = i + 1; j < n; j++)
{
if ((a[i] == a[j]) || (abs(a[i] - a[j]) == abs(i - j)))//不同列和斜线
return 0;
}
return 1;
}
int main()
{
int a[n];
int num, temp;
int i;
int count = 0;
for (num = 0; num < pow(n, n); num++)
{
temp = num;
for (i = 0; i < n; i++)
{
//八进制
a[i] = temp%n;
temp = temp / n;
}
if (place(a))
{
count++;
for (i = 0; i < n; i++)
{
printf("(%d,%d) ", i+1,a[i]+1);
}
putchar('\n');
}
}
printf("total is : %d\n", count);
return 0;
}
(2)递归解:递归的本质是栈,因此第三个方法就是栈。对于递归来说,同样有数组a,作用同上。递归的过程就是函数本身调用本身的过程。在八皇后中,这种递归叫做直接递归;还有一种递归方式是间接递归。递归是一种思考方式,并没有迭代的方式好。以下给出递归的代码。
#include
#include
/*N皇后问题*/
#define N 8
int a[N] = {
0 };
int count = 2;
int space(int row)
{
int j;
for (j = 0; j < row; j++)
{
if ((a[row] == a[j]) || (abs(a[row] - a[j]) == abs(row - j)))//不同列和斜线
return 0;
}
return 1;
}
void dfs(int row)// row一行一个
{
int k;
if (row == N)
{
count += 1;
for ( k = 0; k < N; k++)
printf("(%d,%d)", k + 1, a[k] + 1);
printf("\n");
}
int i;
for( i = 0; i < N; i++)
{
a[row] = i; //列数推移
if (space(row))
dfs(row + 1);
}
}
int main()
{
dfs(0);
printf("总共 %d 个\n", count -2 );
return 0;
}
(3)栈解:对于学过数据结构的人来说,栈并不陌生,它也是一种线性结构,不过它是受限制的,坚持先进后出的原则。你可以把它想像成一个装水的竹筒,只能从一边装水,然后从同一边倒水。下面给出的代码。
#include
#include
#include
#define MaxSize 100
typedef struct
{
int data[MaxSize];//data[i]存放第i个皇后的列号
int top;
} StType;
int count = 0;
int place(StType st, int i, int j)//测试(i,j)是否与1~i-1皇后有冲突
{
int k = 1;
while (k <= i - 1)//j=1到k-1是已放置了皇后的列
{
if ((st.data[k] == j) || (fabs(j - st.data[k]) == fabs(i - k)))
{
return 0;
}
else
k++;
}
return 1;
}
void queen(int n)
{
int i, j, k;
int find = 0;
StType st;
st.top = 0; //top=0时栈为空
st.top++;//将(1,1)进栈
st.data[st.top] = 1;
while (st.top>0)//栈不空时循环
{
i = st.top;//当前皇后为第i个皇后
if (st.top == n)
{
printf("第%d个解:", ++count);
for (k = 1; k <= st.top; k++)
printf("(%d,%d) ", k, st.data[k]);
printf("\n");
}
find = 0;//每次退栈时重新检查是否能放
for (j = 1; j <= n; j++)
if (place(st, i + 1, j))//在i+1行找到一个放皇后的位置(i+1,j)
{
st.top++;
st.data[st.top] = j;
find = 1;
break;
}
if (find == 0)//找不到放皇后的位置,回溯
{
while (st.top>0)
{
if (st.data[st.top] == n)//本列没有可放位置,退栈
st.top--;
for (j = st.data[st.top] + 1; j <= n; j++)//在本列找下一个位置
if (place(st, st.top, j))
{
st.data[st.top] = j;
break;
}
if (j>n)//当前皇后在本列没有可放的位置
st.top--;
else//本列找到一个位置后退出回溯
break;
}
}
}
}
int main()
{
int n;
printf(" 皇后问题(n<20) n=");
scanf("%d", &n);
printf(" %d皇后问题求解如下:\n", n);
queen(n);
printf("\n");
return 0;
}