N皇后

来源:互联网 发布:单机版数据库 编辑:程序博客网 时间:2024/06/09 22:54

对于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 100000int 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;}}}