对于N皇后问题, 用回溯的方法很容易理解, 但是在判重的时候容易超时,因此判重的的方法很重要,下面是我写的三段关于N皇后的代码,只有最后一段在QDUOJ上过了。
第一段:判重方法很蹩脚
#include <stdio.h>
#define M 10000000
int n = 0, num = 0, a[M], array[20][20], count;
void find(int m);
int zero(int m, int i);
int main()
{
scanf("%d", &n);
getchar();
find(1);
printf("%d\n", num);
return 0;
}
void find(int m)
{
int i, x;
if(m > n)
{
num++;
if(num <= 3)
{
for(i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
}
else
{
for(i = 1; i <= n; i++)
{
x = zero(m, i);
if(x == 1 && array[m][i] == 0)
{
a[count++] = i;
array[m][i] = 1;
find(m+1);
array[m][i] = 0;
count--;
a[count] = -1;
}
}
}
}
int zero(int m, int i)
{
int j = 0, x, y, flag[4] = {0};
if(m == 1)
return 1;
x = m - 1;
for(x; x >= 0; x--)
{
if(array[x][i] == 1)
flag[0] =1;
}
x = m - 1;
y = i - 1;
for(x, y; x >=0 && y >= 0; x--, y--)
{
if(array[x][y] == 1)
flag[2] = 1;
}
x = m - 1;
y = i + 1;
for(x, y; x >= 0 && y <= n; x--, y++)
{
if(array[x][y] == 1)
flag[3] = 1;
}
for(x = 0; x < 4; x++)
{
if(flag[x] == 1)
return 0;
}
return 1;
}
第二种方法:从网上取了取经,用一位数组存储棋盘,但是判重的时候还是需要循环
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define M 100000
int array[M], n, num;
int find(int row);
int zero(int row, int col);
int main()
{
int start, end;
scanf("%d", &n);
getchar();
start = clock();
find(1);
end = clock();
printf("%d\n", num);
printf("time is %d\n", end - start);
return 0;
}
int zero(int row, int col)
{
int i;
if(row == 0)
return 1;
for (i = 1; i <= row; ++i) //对棋盘进行扫描
{
if (array[i] == col || abs(i - row) == abs(array[i] - col)) //判断列冲突与斜线上的冲突
return 0;
}
return 1;
}
int find(int m)
{
int i, j;
if(m > n)
{
num++;
if(num <= 3)
{
for(i = 1; i <= n; i++)
printf("%d ", array[i]);
printf("\n");
}
}
else
{
for(i = 0; i <= n; i++)
{
j = zero(m, i);
if(j == 1)
{
array[m] = i;
find(m+1);
array[m] = 0;
}
}
}
}
第三种方法:参考的《算法竞赛入门经典》,方法很巧妙
#include <stdio.h>
int num = 0, n, array[3][30] = {0}, a[20];
void find(int cur);
int main()
{
scanf("%d", &n);
getchar();
find(0);
printf("%d\n", num);
return 0;
}
void find(int cur)
{
int i, j;
if(cur == n)
{
num++;
if(num <= 3)
{
for(j = 0; j < n - 1; j++)
printf("%d ", a[j] + 1);
printf("%d\n", a[n - 1] + 1);
return ;
}
}
else
{
for(i = 0; i < n; i++)
if(!array[0][i] && !array[1][cur + i] && !array[2][cur - i + n])
{
//array[0][i]标记的是列
//array[1][cur + i]标记的是斜对角线(行与列相加是相等的)
//array[2][cur - i + n]标记的是主对角线(行与列相减是相等的, 加n是为了避免cur < i的情况出现)
a[cur] = i;
array[0][i] = 1;
array[1][cur + i] = 1;
array[2][cur - i + n] = 1;
find(cur+1);
array[0][i] = 0;
array[1][cur + i] = 0;
array[2][cur - i + n] = 0;
}
}
}