- 熟练应用C语言制作代码运算输出八皇后全部解的问题
- 8*8格的棋盘上实现全部92种解的输出
- 棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法,运用计算机求解8个皇后问题。基本的解决思路如下:1)解决冲突问题:这个问题包括了行,列,两条对角线。行:规定每一行放一个皇后,不会造成行上的冲突;列:当第1列被某个皇后占领后,则同一列上的所有空格都不能再放皇后,被标记位置为被占领状态。对角线:对角线有两个方向,在同一对角线上的所有点都不能有冲突。2)使用算法分析与设计的知识,用递归法、枚举法、回溯法等解决问题。3)思考要解决的问题:用什么算法分析与设计来描述棋盘,怎样描述棋盘,怎样描述皇后(包括皇后的位置,怎样移动皇后等)。怎样开始程序。4)初步解决问题,列出大纲。
-
1.涉及到的知识基础
在本次八皇后的课程设计中,主要涉及到了的知识有:函数、选择结构、循环结构中的for循环等等,这些在枚举法、回溯、递归等算法中都得到了应用。
1.1函数函数的定义:定义一个函数我们需要确定三部分内容:函数返回值类型、函数的名称、函数的参数。一般形式:数据类型 函数名(参数){函数体}函数的调用与声明如果函数的定义是在调用函数的后面(下面)则需要在调用之前声明函数的定义,否则不需要事先声明。声明的意思是告诉编译器,这个函数的返回值类型、函数名和参数。在调用一个函数时,需要向这个函数传其需要的参数,由函数名和函数调用符()组成,一般形式为:Function(param1, param2, param3 ...);其中Function是函数名称,param1, param2, param3 ...是实参列表,实参可以是常数、变量、表达式等,多个实参用逗号分隔。1.2选择结构(if、while语句)If语句选择结构通过判断条件是否成立,来决定执行哪个分支。选择结构有多种形式,分为:单分支、双分支、多分支(可以嵌套)。单分支:if(条件表达式) 语句/语句块双分支:if (表达式){语句 1}else{语句 2}多分支:if (表达式 1){语句 1}else if (表达式 2){语句 2}else if (表达式3){语句 3}… …1.3循环结构For循环a.一般形式:for(表达式1;表达式2;表达式3){循环语句;} (表达式1为初始化部分,用于初始化循环变量的;表达式2为条件判断部分,用于判断循环时候终止;表达式3为调整部分,用于循环条件的调整。)b.执行步骤:第一,先进行循环控制变量初始化;第二,执行循环终止条件,如果判断结果为真,则进入第三步;如果为假则循环终止并退出;第三,执行循环体;第四,执行循环控制变量增量,转入第二步。
6.
#include <stdio.h>
int queen[8] = {0};
int sum = 0;
int cnt ; //表示摆放了几个皇后,也表示摆放皇后的行数。
int col ; //表示在这一列上摆放了皇后
void greedy(){
while(1){
//在(cnt,col)这个坐标摆放皇后
if(cnt == 1 && queen[0] == 7 && col == 6){ //表示第一行的皇后已经到了第八列且第二行的皇后到了第六列位置,已经摆放不下皇后了就退出循环
break;
}
int isAttack = 0; //用来表示皇后们之间是否能够攻击的到,如果攻击的到就是1,否则就为0
int i=0;
for(i=0;i<cnt;i++){
if(queen[i] == col){ //表示在同一列上
isAttack = 1;
}
int div_row =cnt -i; //表示斜线上的纵坐标之差
int div_col = queen[i]-col; //表示斜线上横坐标之差
if(div_row == div_col ||div_row == -div_col){ //表示在同一斜线上
isAttack = 1;
}
}
if(isAttack == 0){ //表示可以放置
queen[cnt] = col; //记录皇后当前的列数
cnt++; //开始摆放下一个皇后
col = 0; //下一个皇后从第一列开始遍历
if(cnt == 8){ //如果摆满了八个皇后就打印出他们的摆法
for (i = 0 ; i <= 7; ++i) //打印该种摆放方法情况
{
for (int col=0;col<=7;col++)
{
if (col!=queen[i])
{
printf("0|");
}
else
{
printf("1|");
}
}
printf("\n");
}
for(i=0;i<8;i++){
printf("%d ",queen[i]+1);
}
printf("\n");
sum++;
printf("这是第%d种摆法\n",sum);
printf("\n"); //并且摆放种数+1
do{ //越界问题 //回朔
cnt--; //撤回正在摆放的皇后
col = queen[cnt]+1; //往下一个列寻找摆放位置
}while(col>=8);
}
}else{ //表示不能摆放
col++;
while(col>=8){ //回朔
cnt--; //退一格
col = queen[cnt]+1; //上一个皇后往后移一格
}
}
}
printf("总共有%d种摆法\n",sum);
return ;
}
int main(){
greedy();
return 0;
}
7.算法优缺点
优点:回溯法是一种优选的搜索法,又称试探法。按选优条件向前搜索,已达到目标。但当搜索到某一步时,发现原选择并不优或者达不到目标,就退一步重新选择。它的关键是出口语句放置的位置(建议出口语句放在递归函数的第一行),出口语句写在最前面,方便整个函数退出。回溯法用到的核心思想就是递归,过程逻辑清楚,而且执行效率很高。
缺点:抽象性很高,解题过程容易看懂但是手写递归过程很难下笔;时间复杂度高,遇到复杂的问题回溯速度慢。