早上中午晚上好!
这是一道经典的题目,网上相关文章也不胜枚举,(随便百度一下满屏都是),但是自己写了,自己给自己总结一下。
参考的文章:
· 八皇后问题详解(四种解法) 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就有点耗时大了)。递归和循环是能够互相转化的。
算法入门到入坟