C語言實現N皇后問題非遞迴求解
N皇后問題是一個老掉牙的問題了,隨便翻一本演算法書籍都能看到對它的介紹,其實N皇后問題可以用非遞迴方法解決,有效避免N過大時的遞迴工作棧溢出,且佔用的儲存空間較小,運行速度也較快,達到運行速度和空間合理利用的兩全,代碼很簡單,並不複雜,有時簡單也是一種美,意味著可靠和高效。追求程式的複雜和難以理解的編程者不會認同這一點,但對用簡單的設計就可以解決的問題用複雜的資料表示加以描述是沒有必要的。
代碼如下(C語言):
#include <stdio.h>
#include <malloc.h>
#include <math.h>
int place(int i, int k, int *p); //檢查k+1行i列能否放置皇后,能返回1,否則返回0
int find(int n, int *p, int k); //在k+1行搜尋可以放置皇后的位置,找到位置後返回列標,否則返回0
void output(int n, int *p); //輸出n皇后問題的一個解
void main()
{
int k, n;
int m;
int *p;
printf("you want to solve n queens problem\n");
printf("n=");
scanf("%d", &n); //輸入問題規模
p=(int *) malloc(n*sizeof(int)); //p[k]表示k+1行皇后所在列
for (k=0; k<n; k++)
{
p[k]=0; //初始化數組p
}
k=0; //初始化為第一行
m=0; //記錄解的個數變數初始化
loop: if (k==0) //進入或回溯至第一行
{
p[k]=p[k]+1; //試探下一列
if (p[k]>n) //第一行所有列試探完畢,回溯結束
{
goto exit;
}
k++; //試探下一行
goto loop;
}
else
{
if (find(n, p, k)==0) //k+1行沒有找到可放置皇后的位置
{
p[k]=0; //必要的清理
k--; //回溯
goto loop;
}
else
{
p[k]=find(n, p, k); //在k+1行找到的位置賦予p[k]
if (k!=(n-1)) //皇后沒有全部放置完畢
{
k++; //試探下一行
goto loop;
}
else //皇后全部放置成功,找到解
{
m++;
printf("The %dnd solution\n", m);
output(n, p); //輸出解
goto loop; //回溯
}
}
}
exit: ;
printf ("There are %d solutions in total\n", m); //輸出解的個數
}
int place(int i, int k, int *p)
{
int m;
for (m=0; m<k; m++)
{
if ((p[m]==i)||(abs(m-k)==abs(p[m]-i))) //k+1行i列不是合法位置
return (0);
}
return (1); //k+1行i列是合法位置
}
int find(int n, int *p, int k)
{
int i;
i=p[k];
for (i++; i<=n; i++)
{
if (place(i, k, p)==1) //在k+1行找到可放置皇后的列
return (i); //返回該列
}
return (0); //在k+1行沒有找到可放置皇后的列
}
void output(int n, int *p)
{
int i, j;
for (i=0; i<n; i++)
{
for (j=1; j<=n; j++)
{
if (j==p[i])
printf("1 ");
else
printf("0 ");
}
printf("\n");
}
printf("\n");
}
附n皇后問題的遞迴代碼:
該程式段為自己的創作(教科書上現成的代碼沒必要複製粘貼),意義不是很大,因為比較繁瑣,當n<=8時能輸出正確結果,n>8時直接STACKOVERFLOW,所以大家看看就好,並不實用
#include <stdio.h>
#include <math.h>
#include <malloc.h>
#include <stdlib.h>
void print(int n);
void put(int k, int n, int *q, int *p);
void output(int n, int *p);
int law(int k ,int i, int *p);
void main ()
{
int n;
printf ("you want to solve the problem of n queens the n=?\n");
scanf ("%d", &n);
print(n);
}
void print(int n)
{
int number, i;
int *p;
number=0;
p=(int *)malloc(n*sizeof(int));
for (i=0; i<n; i++)
*(p+i)=0;
put(1, n, &number, p);
printf("There are %d solutions in total\n", number);
free(p);
}
void put(int k, int n, int *q, int *p)
{
int i;
if (k==1)
{
(*p)++;
if ((*p)>n)
return;
put(k+1, n, q, p);
}
else
{
i=*(p+k-1);
i++;
while (i<=n)
{
if (law(k, i, p))
{
*(p+k-1)=i;
if (k==n)
{
(*q)++;
printf ("The %dnd solution\n", *q);
output(n, p);
put(k, n, q, p);
}
else
{
put(k+1, n, q, p);
}
break;
}
i++;
}
if (i>n)
{
*(p+k-1)=0;
put(k-1, n, q, p);
}
}
}
void output(int n, int *p)
{
int j, c;
for (j=1; j<=n; j++)
{
for (c=1; c<=n; c++)
{
if (c==*(p+j-1))
printf ("%d", 1);
else
printf ("%d", 0);
}
printf ("\n");
}
printf ("\n");
}
int law(int k ,int i, int *p)
{
int m;
for (m=1; m<k; m++)
{
if ((*(p+m-1)==i)||(abs(m-k)==abs(*(p+m-1)-i)))
return(0);
}
return(1);
}