c语言八皇后问题程序设计.docx
- 文档编号:25689225
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:21
- 大小:120.71KB
c语言八皇后问题程序设计.docx
《c语言八皇后问题程序设计.docx》由会员分享,可在线阅读,更多相关《c语言八皇后问题程序设计.docx(21页珍藏版)》请在冰豆网上搜索。
c语言八皇后问题程序设计
2014年春季学期
《C项目设计》报告
题目:
八皇后问题
学号:
092213112
姓名:
刘泽中
组名:
1
指导教师:
宋东兴
日期:
2014.05.15
一、问题描述
1.八皇后问题:
是一个古老而著名的问题。
该问题是十九世纪著名的数学家高斯1850年提出:
在8×8棋盘上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法?
2.解决八皇后问题的关键在于:
(1)找到合理的数据结构存放棋子的摆放位置。
(2)要有合理的冲突检查算法。
采用的方法是,先把8个棋子摆在棋盘上,每行摆一个,然后去检查这种摆放是否有冲突,如果没有冲突,即找到了一种解决方案。
由于皇后的摆放位置不能通过某种公式来确定,因此对于每个皇后的摆放位置都要进行试探和纠正,这就是“回溯”的思想。
在8个皇后未放置完成前,每行摆放一个皇后,摆放第i个皇后和第i+1个皇后的试探方法是相同的,因此完全可以采用递归的方法来处理。
二、总体设计与分析
1.设计效果
画一个8*8的国际象棋盘,在棋盘某一位置上放一棋子,并让它按从左到右的方向自动运动,用户可以使用光标键调整棋子运动的方向,找出所有可能的摆放方案,将包含指定的棋子的(如3行4列)摆放方案找出并显示出来。
。
2.、总体设计
程序总体分为两大块:
(1)八皇后摆法的寻找;
(2)棋盘及棋子的设计。
3、详细模块
(1)八皇后摆法的寻找:
intchess[8][8]={0};//二维数组表示8*8棋盘,全部清0,(0代表该位没有放棋子)
voidqueen(inti,intn){//i表示从第i行起为后续棋子选择合适位置,n代表n*n棋盘
if(i==n)
output(n);//输出棋盘当前布局;
else{
for(j=0;j chess[i][j]=1;//在第i行,j列上放一棋子 if(! canAttack(i,j))//如果当前布局合法,不受前i-1行的攻击 queen(i+1,n);//递归摆放i+1行 chess[i][j]=0;//移走第i行,j列的棋子 } } } intcanAttack(inti,intj){//判断0到i-1行已摆放的棋子,对[i,j]位置是否可以攻击 for(m=0;m for(n=0;n<8;n++){ if(chess[m][n]==1){ if(m==i||n==j)return1; if(m+n==i+j||m-n==i-j)return1; } } } return0; } voidoutput(){//输出一组解,即打印出8个皇后的坐标 for(inti=0;i<8;i++){ for(intj=0;j<8;j++){ if(chess[i][j]==1){ printf("(%d,%d)",i,j); } } } printf(“\n”); } intmain(){ queen(0,8); return0; } (2)棋盘及棋子的设计: voiddrawBlock(inti,intj){//棋盘的设计(每一个小方块) intx0,y0,x1,y1; x0=ORGX+j*W; y0=ORGY+i*H; x1=x0+W-1; y1=y0+H-1; setcolor(WHITE); rectangle(x0,y0,x1,y1); setfillstyle(1,LIGHTGRAY); floodfill(x0+1,y0+1,WHITE); setcolor(WHITE); line(x0,y0,x1,y0); line(x0,y0,x0,y1); setcolor(BLACK); line(x1,y0,x1,y1); line(x0,y1,x1,y1); } voiddrawBall(Ballball){//棋子的设计 intx0,y0; x0=ball.startX+ball.c*ball.w+ball.w/2; y0=ball.startY+ball.r*ball.h+ball.h/2; setcolor(RED); setfillstyle(1,RED); fillellipse(x0,y0,10,10); } 4.程序设计思路: 先设计程序,找到八皇后的摆放位置,方法是: 先把8个棋子摆在棋盘上,每行摆一个,然后去检查这种摆放是否有冲突,如果没有冲突,即找到了一种解决方案。 采用递归方法和“回溯”思想,找到8*8棋盘上的各种摆法,并把它打印显示出来,共92种。 然后用TC进行图形编程,画出精美的棋盘,设计好棋子,从显示棋盘,显示棋子,上下左右移动棋子,一步一步,减少错误率。 最后,将棋盘棋子和八皇后摆放的代码结合一起,做出可以使用光标键调整棋子运动 方向,找出所有可能的摆放方案,将包含指定的棋子的(如3行4列)摆放方案找出并显示出来的效果。 整个大程序看起来很复杂,但是把其分成二大块,最后再合成,便显得很容易多了。 三、相关代码 1.typedefstruct{//定义一个棋子数据结构 intr,c;//棋子在棋盘上的的行,列坐标 inth,w;//棋子所在方块的高度和宽度 intstartX,startY;//棋盘在屏幕的起始坐标,画棋子定位所用 enumDirectiondir; }Ball; 2.voidinit(){//初始化 intgdriver,gmode; gdriver=DETECT; initgraph(&gdriver,&gmode,"c: \\tc30\\bgi"); cleardevice(); } 3.voiddrawTable(){//画棋盘 inti,j,size; for(i=0;i for(j=0;j drawBlock(i,j);//画小方块 } } size=imagesize(50,50,50+7*W+W-1,50+7*H+H-1);//计算大小,保存到缓存区 buff1=(void*)malloc(size); getimage(50,50,50+7*W+W-1,50+7*H+H-1,buff1);//将整个棋盘保存的缓存区 } 4.voiddrawBlock(inti,intj){//参数代表小方块在棋盘上的第i行,第j列intx0,y0,x1,y1; x0=ORGX+j*W; y0=ORGY+i*H; x1=x0+W-1; y1=y0+H-1; setcolor(WHITE); rectangle(x0,y0,x1,y1); setfillstyle(1,LIGHTGRAY);//设置小方块的填充色 floodfill(x0+1,y0+1,WHITE); setcolor(WHITE);//增加立体感,设置白色 line(x0,y0,x1,y0); line(x0,y0,x0,y1); setcolor(BLACK); line(x1,y0,x1,y1); line(x0,y1,x1,y1); } 5.voiddrawBall(Ballball){//画棋子 intx0,y0; x0=ball.startX+ball.c*ball.w+ball.w/2;//计算圆心坐标 y0=ball.startY+ball.r*ball.h+ball.h/2; setcolor(RED); setfillstyle(1,RED); fillellipse(x0,y0,10,10); } 6.voidmove(Ball*ball,introls,intcols){//棋子移动switch(ball->dir){ caseKEY_UP: ball->r--;;if(ball->r<0)ball->r=rols-1;break; caseKEY_DOWN: ball->r++;if(ball->r==rols)ball->r=0;break; caseKEY_LEFT: ball->c--;if(ball->c<0)ball->c=cols-1;break; caseKEY_RIGHT: ball->c++;if(ball->c==cols)ball->c=0;break; } } 7.voidinit2(Ball*ball,intr,intc,intsize,intx0,inty0){//初始化一个棋子 ball->r=r; ball->c=c; ball->h=ball->w=size; ball->startX=x0; ball->startY=y0; } 8.voidclearBall(){//将缓存区的棋盘拿出来 putimage(50,50,buff1,COPY_PUT); } 9.voidchangeDir(Ball*ball,enumDirectiondir){//运动方向 ball->dir=dir; } 10.voidfun(Ballball){//当前棋子的坐标 xx=ball.r; xy=ball.c; } 11.voidqueen(inti){//i表示从第i行起为后续棋子选择合适位置 intj; if(i==8) outputa(); else{ for(j=0;j<8;j++){ chess[i][j]=1;//二维数组表示8*8棋盘(0代表该位没有放棋子) if(! canAttack(i,j))//如果当前布局可行,不受i-1行的攻击 queen(i+1);//递归摆放i+1行 chess[i][j]=0;//移走第i行,j列的棋子 } } } 12.intcanAttack(inti,intj){//判断0到i-1行已摆放的棋子, 对[i,j]位置是否可以攻击 intm,n; for(m=0;m for(n=0;n<8;n++){ if(chess[m][n]==1){ if(m==i||n==j)return1; if(m+n==i+j||m-n==i-j)return1; } } } return0; } 13.voidoutputa(){ BallmyBall; inti,j,a=0,b=0; for(i=0;i<8;i++){//输出一组解,坐标分别保存到两个数组里 for(j=0;j<8;j++){ if(chess[i][j]==1){ fa[a++]=i; fb[b++]=j; } } } if(fam==0){//判断是否为全部输出,fam为1时输出全部92种解 for(i=0;i<8;i++) if(fa[i]==xx&&fb[i]==xy){//如果有坐标与当前棋子坐标相同时 delay(800);//延时800毫秒 clearBall();//清空棋子 flap++;//计数当前棋子位置满足要求的个数 for(i=0;i<8;i++){//画出一组解 init2(&myBall,fa[i],fb[i],W,ORGX,ORGY); drawBall(myBall); } } } else{//否则全部输出92种解 delay(800); clearBall(); for(i=0;i<8;i++){ init2(&myBall,fa[i],fb[i],W,ORGX,ORGY); drawBall(myBall); } } t++;//计数器,用来计算总共多少组解 a=b=0; } 四、调试分析 1.程序初始界面: 2.随机移动到某点: 3.按ENTER键,寻找包含当前棋子的解: 4.按TAB键,显示全部92种解: 五: 软件说明书及设计总结 1.软件说明: 用户运行程序,可自由移动棋子,当按ENTER键时,可显示包含当前用户选择棋子位所有八皇后的解,当显示完毕后,下方会输出八皇后解的总数以及当前坐标位置的解的个数。 当按下TAB键时,屏幕以800毫秒的延时显示全部92种八皇后的解。 当用户按ESC键时,退出本程序。 2.总结: 本程序虽然能显示所有摆法,但是还是有很多不足的地方,比如不能够多姿多彩的显示,由于自己本身编程能力问题,以及时间问题,许多细节并不是处理的很好,使得程序的功能并不是很丰富,界面也不是很美观,但是本程序也有其优点: 简洁、明了,易于操作,并且可以把所有的解一目了然的输出直观的显示出来。 在实际操作过程中对犯的一些错误还会有意外的收获,对老师上课所讲的一些函数的应用更有了深刻的理解,这次实训是老师给了范例程序,经过自己的改写,基本实现了要求,以后会尽量自己动手去查资料等等。 六、附录: 部分程序代码 ******************************START******************************* #include #include #include #include #include"bios.h" #defineROW8 #defineCOL8 #defineW40 #defineH40 #defineORGX50 #defineORGY50 #defineKEY_UP0x4800 #defineKEY_DOWN0x5000 #defineKEY_LEFT0x4b00 #defineKEY_RIGHT0x4d00 #defineESC0x11b #defineENTER0x1c0d #defineTAB0xf09 into=0,p=0,fam=0,flap=0; intxx=3,xy=3,t=0,we=0; intfa[10]={0,1,2,3,4}; intfb[10]={3,1,6,2,5}; intchess[8][8]={0}; intstr[20]; voidoutputa(); void*buff1; voiddrawBlock(inti,intj); typedefstruct{ intr,c; inth,w; intstartX,startY; enumDirectiondir; }Ball; voidinit(){ intgdriver,gmode; gdriver=DETECT; initgraph(&gdriver,&gmode,""); cleardevice(); } voiddrawTable(){ inti,j,size; for(i=0;i for(j=0;j drawBlock(i,j); } } size=imagesize(50,50,50+7*W+W-1,50+7*H+H-1); buff1=(void*)malloc(size); getimage(50,50,50+7*W+W-1,50+7*H+H-1,buff1); } voiddrawBlock(inti,intj){ intx0,y0,x1,y1; x0=ORGX+j*W; y0=ORGY+i*H; x1=x0+W-1; y1=y0+H-1; setcolor(WHITE); rectangle(x0,y0,x1,y1); setfillstyle(1,LIGHTGRAY); floodfill(x0+1,y0+1,WHITE); setcolor(WHITE); line(x0,y0,x1,y0); line(x0,y0,x0,y1); setcolor(BLACK); line(x1,y0,x1,y1); line(x0,y1,x1,y1); } voidinit2(Ball*ball,intr,intc,intsize,intx0,inty0){ ball->r=r; ball->c=c; ball->h=ball->w=size; ball->startX=x0; ball->startY=y0; } voiddrawBall(Ballball){ intx0,y0; x0=ball.startX+ball.c*ball.w+ball.w/2; y0=ball.startY+ball.r*ball.h+ball.h/2; setcolor(RED); setfillstyle(1,RED); fillellipse(x0,y0,10,10); } voidchangeDir(Ball*ball,enumDirectiondir){ ball->dir=dir; } voidmove(Ball*ball,introls,intcols){ switch(ball->dir){ caseKEY_UP: ball->r--;;if(ball->r<0)ball->r=rols-1;break; caseKEY_DOWN: ball->r++;if(ball->r==rols)ball->r=0;break; caseKEY_LEFT: ball->c--;if(ball->c<0)ball->c=cols-1;break; caseKEY_RIGHT: ball->c++;if(ball->c==cols)ball->c=0;break; } } voidclearBall(){ putimage(50,50,buff1,COPY_PUT); } voidqueen(inti){ intj; if(i==8) outputa(); else{ for(j=0;j<8;j++){ chess[i][j]=1; if(! canAttack(i,j)) queen(i+1); chess[i][j]=0; } } } intcanAttack(inti,intj){ intm,n; for(m=0;m for(n=0;n<8;n++){ if(chess[m][n]==1){ if(m==i||n==j)return1; if(m+n==i+j||m-n==i-j)return1; } } } return0; } voidoutputa(){ BallmyBall; inti,j,a=0,b=0; for(i=0;i<8;i++){ for(j=0;j<8;j++){ if(chess[i][j]==1){ fa[a++]=i; fb[b++]=j; } } } if(fam==0){ for(i=0;i<8;i++) if(fa[i]==xx&&fb[i]==xy){ delay(800); clearBall(); flap++; for(i=0;i<8;i++){ init2(&myBall,fa[i],fb[i],W,ORGX,ORGY); drawBall(myBall); } } } else{ delay(800); clearBall(); for(i=0;i<8;i++){ init2(&myBall,fa[i],fb[i],W,ORGX,ORGY); drawBall(myBall); } } t++; a=b=0; } voidfun(Ballball){ xx=ball.r; xy=ball.c; } intmain(){ intkey; inti; BallmyBall; Ballball; init(); drawTable(); init2(&myBall,3,3,W,ORGX,ORGY); drawBall(myBall); settextstyle(0,0,1); textcolor(RED); gotoxy(22,2); printf("EightQueens"); while (1){ key=bioskey(0); switch(key){ caseKEY_UP: changeDir(&myBall,KEY_UP);break; caseKEY_DOWN: changeDir(&myBall,KEY_DOWN);break; caseKEY_LEFT: changeDir(&myBall,KEY_LEFT);break; caseKEY_RIGHT: changeDir(&myBall,KEY_RIGHT);break; caseESC: exit(0); } if(key==ENTER){ fun(myBall); fam=0; queen(0); gotoxy(10,25); printf("total=%d",t); gotoxy(30,25); printf("in(%d,%d)=%d",xx+1,xy+1,flap); flap=0; t=0; } elseif(key==TAB){ fam=1;queen(0); t=0;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 皇后 问题 程序设计