C语言实现经典八皇后问题

早上中午晚上好! 

这是一道经典的题目,网上相关文章也不胜枚举,(随便百度一下满屏都是),但是自己写了,自己给自己总结一下。


参考的文章:

· 八皇后问题详解(四种解法)  C++实现,大佬,总结了实现题目的多种方法思路。

·【数据结构】递归---八皇后问题

·经典问题——八皇后问题:最适合C语言初学者的解法  比较详细的解决思路。C语言。

看了别人的解法我好菜啊


问题描述

分析和思路

基本实现思路就是回溯。 

我的第一个想法是8个for,暴力的穷举,但是这并非合理,浪费空间,而且提交以后超时

我的思路:回溯并且逐行判断。

起始条件:第一行第一列开始,向下判断。

终止条件:第一行8列全部尝试结束。 

判断条件:①把已经有的棋子的列数存放在一维数组中②用数学计算表示“同行同列同对角”关系。

循环递归:行数i的增加或者减少,列数j的增加或者减少。 

伪代码:

//从第一行开始遍历
while(行数i>=0)
{
基于前i-1行判断本行能不能放下

if(能)
    {
    if(最后一行)
          {找到了一种方案;
           找全最后一行方案:
           后退,寻找更多解;    
            }
    else
        {i++进入下一行}
    }
else//不能
{回溯;i--;}
}

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。 

代码 

如果对n赋值,就是n皇后问题。

#include<stdio.h>
int main()
{//back~flog=1 else~flag=0
	int i=0,j=0,m,count=0,flag=0;
	int chess[15]={0};//存放已经判断的个数
	int n;//scanf("%d",&n);
 	n=8;
	for(i=1,flag=0;i>=0;) //退出的方法:行数回溯到0 
	{		
			//printf("\n****当前行:%d\t",i);
			if(flag) j=chess[i]+1;
			else j=0;
			
			for(;j<n;j++)
			 {//对于该行每一列元素进行尝试 
			 	for(m=0;m<i;m++)
			 	{//检查之前的坐标是否影响这次的放入 
			 		if((chess[m]!=j)&&(chess[m]-j+m-i)&&((chess[m]-j)!=(m-i)) ) 
			 		 continue;
					else{	break;}//出现了重复退出 
					}
				if(m==i)	break;//说明一直没有影响 
			} 
			if(j<n)//添加这一行 i++ 
			{	chess[i]=j;
				//printf("push(%d%d)\n",i,j);
				if(i<n-1){i++;flag=0;continue;}
				if(i==n-1)
				{//最后一行:
					count++;
					for(m=0;m<n-1;m++)
						printf("%d ",chess[m]+1);
						printf("%d\n",j+1);
					j=1+chess[n-1];
					for(;j<n;j++)
					{//试全部格子
						for(m=0;m<n-1;m++)
			 			{//检查之前的坐标是否影响这次的放入 
			 			if((chess[m]!=j)&&(chess[m]-n+1+m-j)&&(chess[m]-j)!=(m-n+1) ) 
			 		 		continue;
					 	else	break;
						}//出现了重复退出 
						if(m==n-1)	{
							count++;
							for(m=0;m<n-1;m++)	printf("%d ",chess[m]+1);	
							printf("%d\n",j+1);}
									
					}//试完全部方案,back
					i--;flag=1; 
					continue;		
				}
			}//回溯上一行 i-- 删掉本行的标记 		 
			else	{i--;flag=1;continue;
			}		
	}
		printf("共计%d个方案",count);	return 0;	
}

实践中的问题和思考

·我感觉这个是DFS,每一次找到头,每一次遍历一个解答树的子树。

·写的时候进了好几次死循环。到底什么时候是++什么时候--真的卡了很久。

·关于数据结构问题:一开始看见棋盘就想N*N大小数组,但是完全没有必要,我们只需要每行的位置信息,只需要“列值”这一个数字。开一个一维数组就完全够用。

·关于循环变量设值问题:对于i,很好说,从0开始一直到n-1(n皇后问题),有解i++,无解i--;但是对于j的在每行(每个i值)不是很会处理,最后选择添加flag参数,区别“前进”和“后退”时候对于j的初始化值不同,判断“从那一列搜索开始”。

·其实定义递归函数思路可能更加流畅,但是我担心函数递归耗费时间,(我的代码n皇后在n=15就有点耗时大了)。递归和循环是能够互相转化的。

算法入门到入坟

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值