N皇后——递归和非递归
来源:互联网 发布:万能小偷网站源码 编辑:程序博客网 时间:2024/05/17 03:37
总结: 8皇后的解有92种,但由于对称性,真正独立的解是12种
其中一种方案只能衍生出4个答案的情况,
所以不重复的方案是12个,其中一个是对称图形,最终结果是11*8+1*4=92。
那个特殊方案就是:
. . X . . . . .
. . . . X . . .
. X . . . . . .
. . . . . . . X
X . . . . . . .
. . . . . . X .
. . . X . . . .
. . . . . X . .
1.递归解
(1)
#include <stdio.h>
#include <stdlib.h>
const int N=20; //最多放皇后的个数
int q[N]; //各皇后所在的行号
int cont = 0; //统计解得个数
//输出一个解
void print(int n)
{
cont++;
printf("第%d个解:",cont);
for(int i=1;i<=n;i++)
printf("%d",q[i]);
printf("/n");
for(i=0;i<n;i++) //col
{
for(int j=0;j<n;j++) //row
{
if(q[j+1]!=i+1)
printf("x ");
else
printf("Q ");
}
printf("/n");
}
}
//检验第k列的i行上是否可以摆放皇后
int find(int i,int k)
{
int j=1;
while(j<k) //j=1~k-1是已经放置了皇后的列
{
//第j列的皇后是否在i列或(q[j],j)与(i,k)是否是同对角线
if(q[j]==i||abs(j-k)==abs(q[j]-i))
return 0;
j++;
}
return 1;
}
//放置第k个皇后到第k列上
void place(int k,int n)
{
if(k>n)
print(n);
else
for(int i=1;i<=n;i++)
if(find(i,k))
{
q[k] = i;
place(k+1,n); //递归总是在成功完成了上次的任务的时候才做下一个任务
}
}
int main()
{
int n;
printf("请输入皇后的个数(n<=20),n=:");
scanf("%d",&n);
if(n>20)
printf("n值太大,不能求解!/n");
else
{
printf("%d皇后问题求解如下(每列的皇后所在的行数):/n",n);
place(1,n); //问题从最初状态解起
printf("/n");
}
return 1;
}
(2)
#include <stdio.h>
#include <stdlib.h>
int result = 1;
int chess[8];
// 函数:打印结果
void show_chess(void)
{
int i;
printf("Result - %d/n", result);
for (i = 1; i <= 8; i++)
{
printf("(%d): %d/n", i, chess[i]);
}
++result;
}
// 根据前面几行的子,检查这一行所放的子是否合法
int check( int n )
{
int i;
for (i = 1; i <= n - 1; i++)
{
if (chess[n] == chess[i] + (n - i) ||
chess[n] == chess[i] - (n - i) ||
chess[n] == chess[i] )
return 0;
}
return 1;
}
// 递归函数:放子
void putchess( int n )
{
int i;
if (n <= 8)
{
for (i = 1; i <= 8; i++) // 将第n行从第一格(i)开始往下放
{
chess[n] = i;
if (check(n) == 1) // 若可放,则检查是否放满
{
if (n == 8)
show_chess(); // 若已放满到8行时,则表示找出一种解,打印出来
else
putchess(n + 1); // 若没放满则放下一行 putchess(n+1)
}
}
}
}
// 主程序
int main()
{
printf("This is for 8 X 8 matrix./n");
putchess(1); // 从每一行开始放子
return 0;
}
2.非递归解
(1)
#include <iostream.h>
#define QUEEN 8 //皇后数量
int queen[QUEEN] ; //下标代表所在列号,值代表所在行号,
//如queen[1]=2表示第1列第2行有个皇后
bool col_YN[QUEEN] ; //棋局的每一行是否有棋,有则为1,无为0 ;
bool passive_YN[2*QUEEN-1] ; //斜率为1的斜线方向上是否有棋,共有2*QUEEN-1个斜线
bool negative_YN[2*QUEEN-1] ; //斜率为负1的斜线方向上是否有棋
//用全局变量,因全局数组元素值自动为0
int main()
{
int col = 0 ;//游标,当前移动的棋子(以列计)
bool flag = false ; //当前棋子位置是否合法
queen[0] = -1 ; //第0列棋子准备,因一开始移动的就是第0列棋子
int count = 0 ; //一共有多少种解法的计数器 ;
while(col>=0 ) //跳出条件是回溯到无法回溯时
{
queen[col]++ ; //col列上的皇后走到下一行试试
if(queen[col] >= QUEEN) //当前列全部走完
{
queen[col] = -1 ; //当前列棋子置于准备状态
col-- ; //回溯到上一列的棋子
if(col>=0) //回溯时要清理如下行,斜线的标志位
{
col_YN[queen[col]] = false ;
passive_YN[queen[col] + col] = false ;
negative_YN[QUEEN-1 + col - queen[col]] = false ;
}
}
else
{
//先判断棋子所在行没有棋子
if(col_YN[queen[col]] == false)
{
flag = true ;
//以下检查当前棋子是否与之前的棋子斜线相交
if( passive_YN[queen[col] + col] == true || negative_YN[QUEEN-1 + col - queen[col]] == true)
flag = false ;
else
flag = true ;
if(flag) // flag为真表示位置合法
{
if(col == QUEEN-1) //列到达最后,即最后一个皇后也找到位置,输出解
{
count++ ; //解法的数目加一 ;
cout<<"***第"<<count<<"种解法***"<<endl ;
for(int i=0;i<QUEEN;i++)
cout<<"第"<<i<<"列皇后在第"<<queen[ i ]<<"行"<<endl;
}
col_YN[queen[col]] = true ;// 当前行设为有棋子
passive_YN[queen[col] + col] = true ;//当前行正斜率方向有棋子
negative_YN[QUEEN-1 + col - queen[col]] = true ; //当前行负斜率方向 上也有棋子
col++ ;
if(col >= QUEEN)
{ // 找到解后再次回溯找另外的解,这同上面无解回溯是一样的
col-- ;
col_YN[queen[col]] = false ;
passive_YN[queen[col] + col] = false ;
negative_YN[QUEEN-1 + col - queen[col]] = false ;//原理同回溯
}
flag = false ;
}
}
}
}
cout<<QUEEN<<"皇后问题一共有"<<count<<"种解法"<<endl ;
return 0 ;
}
(2)利用栈模拟
#include<iostream>
#include<iomanip>
#include<cmath>
#include<stack>
using namespace std;
//利用递归求解皇后问题 x[i]表示皇后放在第i行第x[i]列
static int count;
//判断如果皇后放在第i行,第j列是否与前面的皇后冲突
bool place(int i,int j,int* path)//path存放路径
{
int row;
for(row=0;row<i;row++)
if(j==path[row]||abs(row-i)==abs(path[row]-j))//在同一列列或同一条斜线上
return false;
return true;
}
//利用栈来模拟递归,在某个扩展节点出处,将所有符合条件的节点加入到里面
struct pos
{
int row;
int col;
};
//找到当前最合适的节点,如果没有找到则返回-1
int find_col(int row,int col,int* path,int n)
{
int j;
for(j=col;j<n;j++)
{
if(place(row,j,path))
return j;
}
if(j==n)
return -1;
}
//利用栈来模拟八皇后问题
void stack_stimu(int n,int* path)
{
stack<struct pos> s;
int currow=0;
int flag=0;
//主要结构分为两部分,第一 按照正常顺序寻找节点
//然后找出回溯的情况:在八皇后问题中主要有两中:1.到达结尾 找出路径 2.当前行没有满足条件的位置
while(true)
{
if(currow<n)
{
int col=find_col(currow,0,path,n);
if(col!=-1)
{
pos node;
node.row=currow;
node.col=col;
s.push(node);
path[currow]=col;
currow++;
}
else
flag=1;
}
else
{
for(int i=0;i<n;i++)
cout<<setw(5)<<left<<path[i]+1;
cout<<endl;
count++;
flag=1;
}
// 进行回溯
if(flag==1)
{
//描述了回溯的过程
while(!s.empty())
{
pos temp=s.top();
if(temp.col!=n-1) //由temp.col!=7改为temp.col!=n-1
{
//查找当前最适合的节点,并入栈
int j=find_col(temp.row,temp.col+1,path,n);
if(j!=-1)
{
pos node;
node.row=temp.row;
node.col=j;
s.pop();
s.push(node);
path[temp.row]=j;
currow=temp.row+1;
flag=0;
break;
}
else
s.pop();
}
else
s.pop();
}
if(s.empty())
return;//函数的出口处
}
}
}
int main()
{
cout<<"Queen Place Problem:"<<endl;
cout<<"Input the value of n"<<endl;
int n;
cout<<" n>";
cin>>n;
int* path=new int[n];
//初始化
for(int i=0;i<n;i++)
path[i]=-1;
stack_stimu(n,path); //利用栈来模拟八皇后问题
cout<<"the count is: "<<count<<endl;
return 0;
}
(3)
#include<stdio.h>
#define NUM 8 /*定义数组的大小*/
int a[NUM+1];
int main()
{
int i,k,flag,not_finish=1,count=0;
i=1; /*正在处理的元素下标,表示前i-1个元素已符合要求,正在处理第i个元素*/
a[1]=1; /*为数组的第一个元素赋初值*/
printf("The possible configuration of 8 queens are:/n");
while(not_finish) /*not_finish=1:处理尚未结束*/
{
while(not_finish&&i<=NUM) /*处理尚未结束且还没处理到第NUM个元素*/
{
for(flag=1,k=1;flag&&k<i;k++) /*判断是否有多个皇后在同一行*/
if(a[k]==a[i])flag=0;
for(k=1;flag&&k<i;k++) /*判断是否有多个皇后在同一对角线*/
if((a[i]==a[k]-(k-i))||(a[i]==a[k]+(k-i))) flag=0;
if(!flag) /*若存在矛盾不满足要求,需要重新设置第i个元素*/
{
if(a[i]==a[i-1]) /*若a[i]的值已经经过一圈追上a[i-1]的值*/
{
i--; /*退回一步,重新试探处理前一个元素*/
if(i>1&&a[i]==NUM)
a[i]=1; /*当a[i]为NUM时将a[i]的值置1*/
else if(i==1&&a[i]==NUM)
not_finish=0; /*当第一位的值达到NUM时结束*/
else a[i]++; /*将a[i]的值取下一个值*/
}
else if(a[i]==NUM) a[i]=1;
else a[i]++; /*将a[i]的值取下一个值*/
}
else if(++i<=NUM)
if(a[i-1]==NUM) a[i]=1; /*若前一个元素的值为NUM则a[i]=1*/
else a[i]=a[i-1]+1; /*否则元素的值为前一个元素的下一个值*/
}
if(not_finish)
{
++count;
printf((count-1)%3?" [%2d]: ":" /n[%2d]: ",count);
for(k=1;k<=NUM;k++) /*输出结果*/
printf(" %d",a[k]);
if(a[NUM-1]<NUM) a[NUM-1]++; /*修改倒数第二位的值*/
else a[NUM-1]=1;
i=NUM-1; /*开始寻找下一个足条件的解*/
}
}
}
- N皇后——递归和非递归
- N皇后问题递归和非递归效率测试
- N皇后问题的非递归回溯和递归回溯
- 8皇后 n皇后 非递归
- 回溯法解决N皇后问题——递归与非递归求解
- 八皇后问题--递归和非递归
- NOJ1267 N皇后(非递归算法)
- NOJ1267 N皇后(非递归算法)
- n皇后问题【非递归回溯】
- 非递归求N皇后问题
- N皇后问题的非递归算法
- N皇后问题非递归求解
- N 皇后问题 —— 递归求解
- 八皇后问题(递归、非递归——回溯)
- N皇后问题递归与非递归解法
- N皇后问题的递归与非递归解法
- 8皇后 n皇后 递归
- 递归求N皇后
- TOJ 1296 Prime Distance
- 在windows7中搭建Apache+PHP+MySQL平台
- Watir vs. Selenium
- Watir vs. Selenium vs. Sahi
- 哈哈
- N皇后——递归和非递归
- Firefox - 更新 - 3.6
- DES算法使用示例
- volatile 介绍(转载)
- Java Collections Framework(Java 集合架构)来学习Java定义的一些ADT
- htmlparser使用指南
- 今天逛论坛看到一段不错的程序,视频播放程序
- 无心插柳柳成荫
- 很高兴来这里