上机报告.docx
- 文档编号:28658012
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:33
- 大小:151.18KB
上机报告.docx
《上机报告.docx》由会员分享,可在线阅读,更多相关《上机报告.docx(33页珍藏版)》请在冰豆网上搜索。
上机报告
P116:
应用题
5:
农夫过河问题
1)问题的需求分析
此问题要求比较明确,完成对农夫过河过程的模拟,采用了广度优先搜索和深度优先搜索两种算法来解决。
2)抽象数据类型的设计(或模块功能的划分)
农夫、狼、白菜、羊,用一个四元组(0,0,0,0)来表示,其中0表示在起始岸边,1表示在目的岸边,可以映射到整数的二进制的第四位上去来表示状态,比如说0表示(0,0,0,0),即所有的东西都在起始岸边。
用一个一位数组来存储当前节点的前驱,便于结果输出。
采用广度优先搜索时,设计出队列来存储状态。
功能模块主要分为
建立队列的基本操作,分别判断当前猎人,狼,羊,白菜的位置情况,判断当前状态是否安全,广度优先搜索,深度优先搜索
3)算法与数据结构的设计
广度优先搜索:
将起始状态入队,当队列不为空且没有达到最终状态时,依次遍历当前状态的所有可能的可能移动情况,依次判断各种情况下产生的新状态是否安全且没有被访问过,如果是,就将新的状态依次入队,同时更新记录数组的值,直到判断条件不成立。
然后输出结果,只有一组解。
深度优先搜索(递归):
输出:
当达到最终状态时即route[15]!
=-1,输出结果
否则依次遍历当前状态的所有可能的可能移动情况,依次判断各种情况下产生的新状态是否安全且没有被访问过,如果是就记录当前的位置信息,执行递归调用新状态,在递归调用返回的时候将位置信息清掉回溯。
4)算法的精化与程序的实现
一:
头文件head.h
#ifndefhead_h
#definehead_h
#include
#include
#include
usingnamespacestd;
typedefintDatatype;
structseqqueue//队列
{
intMAXMUM;
intf,r;//指向队头和队尾
Datatype*s;
};
typedefseqqueue*psequque;//顺序栈类型的指针类型
pseququecreateEmpty_seq(intm);//创建一个空队列
pseququeinitstack();//初始化建立一个队列
intisempty(pseququepastack);//判断是否为空队列
voidenqueue_seq(pseququepastack,Datatypex);//入队,在尾部插入元素
voiddequeue_seq(pseququepastack);//出队
DatatypefrontQueue(pseququepastack);//取栈队头元素
voidshow(pseququepstack);//输出元素队列,按出队操作顺序
voidfreemo(pseququepstack);//释放队列内存
intgetlength(pseququepastack);//获得队列的长度
#endif
二:
head.cpp文件
#include"head.h"
pseququecreateEmpty_seq(intm)//创建一个空队列
{
pseququepalist=(psequque)malloc(sizeof(structseqqueue));
if(palist!
=NULL)
{
palist->s=(Datatype*)malloc(sizeof(Datatype)*m);
if(palist->s)
{
palist->MAXMUM=m;
palist->f=0;//队头指向队列首部元素
palist->r=0;//队尾指向尾部的下一个位置
returnpalist;
}
elsefree(palist);
}
printf("outofspace!
!
\n");
returnNULL;
}
pseququeinitstack()
{
printf("请输入最大长度:
");
intm;
scanf("%d",&m);
pseququepstack=createEmpty_seq(m);
printf("请输入初始队列的数目:
");
intn;
scanf("%d",&n);
int*a;
a=newint[n];
printf("请输入初始队列的元素:
");
for(inti=0;i scanf("%d",a+i); for(inti=0;i enqueue_seq(pstack,a[i]); delete[]a; returnpstack; } intisempty(pseququepastack)//判断是否为空队列 { returnpastack->f==pastack->r; } voidenqueue_seq(pseququepastack,Datatypex)//入队 { if(pastack==NULL) { printf("队列地址无效\n"); return; } if(pastack->f==(pastack->r+1)%pastack->MAXMUM)//队列元素已满 { printf("FULLQUEUE! \n"); return; } else{ pastack->s[pastack->r]=x;//赋值 pastack->r=(pastack->r+1)%pastack->MAXMUM;//队尾位置循环右移 } } voiddequeue_seq(pseququepastack)//出栈,弹栈 {if(pastack==NULL) { printf("队列地址无效\n"); return; } if(pastack->f==pastack->r)//已经空队 { printf("EmptyQUEUE! \n"); return; } else { pastack->f=(pastack->f+1)%pastack->MAXMUM;//队头右移动 } } DatatypefrontQueue(pseququepastack)//取队头元素 { if(pastack==NULL) { printf("队列地址无效\n"); return0; } if(pastack->r==pastack->f)//已经空栈 { printf("已经是空队列\n"); return0; } else { returnpastack->s[pastack->f];//返回队头指针对应的值 } } voidshow(pseququepstack)//输出队列元素,按出队操作顺序 { if(pstack==NULL) { printf("队列地址无效\n"); return; } if(pstack->r==pstack->f)//已经空队列 { printf("已经是空栈\n"); return; } intm=pstack->r; printf("队列%d个为: ",getlength(pstack)); for(inti=pstack->f;i! =pstack->r;) {printf("%d",pstack->s[i]); i=(i+1)%pstack->MAXMUM; } printf("\n"); } voidfreemo(pseququepstack)//释放队列内存 { if(pstack==NULL) { printf("队列地址无效\n"); return; } free(pstack->s); free(pstack); } intgetlength(pseququepastack) { return(pastack->r-pastack->f+pastack->MAXMUM)%pastack->MAXMUM; } 三: main.cpp文件 #include"head.h" intfarmer(intlocation)//判断农夫的位置,返回值为1表示农夫在南岸,即目的岸边 { return0! =(location&0x08); } intwolf(intlocation)//判断狼的位置,返回值为1表示狼在南岸,即目的岸边 { return0! =(location&0x04); } intcabbage(intlocation)//判断白菜的位置,返回值为1表示白菜在南岸,即目的岸边 { return0! =(location&0x02); } intgoat(intlocation)//判断羊的位置,返回值为1表示羊在南岸,即目的岸边 { return0! =(location&0x01); } //安全状态的判断函数 //若安全则返回值为1 intsafe(intlocation) { if(wolf(location)==goat(location)&&farmer(location)! =wolf(location))//狼和羊在同一岸边,且猎人不在同一岸边 return0; if(goat(location)==cabbage(location)&&farmer(location)! =goat(location)) return0; return1; } //农夫过河问题,队列求解,广度优先遍历 voidfarmerproblem() { inti,location,newlocation; intmovers;//代表移动的物品,001表示移动羊,010表示移动白菜,100表示移动狼 introute[16];//用于记录路径 pseququemovto; movto=createEmpty_seq(20);//创建空队列 enqueue_seq(movto,0x00);//初始状态入队 for(inti=0;i<16;i++) route[i]=-1; route[0]=0; while(! isempty(movto)&&route[15]==-1) { location=frontQueue(movto);//取队头元素 dequeue_seq(movto);//删除队头元素 for(movers=1;movers<=8;movers=movers<<1) if(((location&0x08)! =0)==((movers&location)! =0)) {//判断农夫与移动的物品是否在同一岸边 newlocation=location^(0x08|movers); if(safe(newlocation)&&(route[newlocation]==-1)) {//新状态安全且尚未处理 route[newlocation]=location;//记录新状态的前驱 enqueue_seq(movto,newlocation);//新状态入队 } } } //打印输出路径 if(route[15]==-1) { printf("NOsolution! ! \n"); } else { printf("thepathis: \n"); inta[16],k=0;//k个元素 for(inti=15;i>=0;i=route[i]) {a[k++]=i; if(i==0)break; } //将k个元素倒序 for(inti=0;i { intn=a[i]; a[i]=a[k-i-1]; a[k-i-1]=n; } for(inti=0;i printf("%d->",a[i]); printf("\n"); printf("thelocationis: %d\n",a[0]); for(inti=1;i { printf("thelocationis: %d",a[i]); intm=a[i]^a[i-1]; if(m==8) { printf("farmer\n"); } elseif(m==9) { printf("farmergoat\n"); } elseif(m==10) { printf("farmercabage\n"); } else { printf("farmerwolf\n"); } } } } //农夫过河问题,递归求解,深度优先遍历,回溯 voidfarmerproblem1(introute[16],intlocation) { if(route[15]! =-1)//结束条件,输出所有解 { for(inti=15;i>=0;i=route[i]) {printf("thelocationis: %d\n",i); if(i==0)break; } route[15]=-1; } else { for(inti=1;i<=8;i=i<<1)//i表示移动的物品 { if(((location&0x08)! =0)==((i&location)! =0)) {//判断农夫与移动的物品是否在同一岸边 intnewlocation=location^(0x08|i); if(safe(newlocation)&&(route[newlocation]==-1)) { route[newlocation]=location; farmerproblem1(route,newlocation); route[newlocation]=-1; } } } } } voidmain() {printf("广度优先搜索结果: \n"); farmerproblem(); introute[16]; for(inti=0;i<16;i++) route[i]=-1; intlocation=0; printf("深度优先搜索结果: \n"); farmerproblem1(route,location); } 5)程序的调试与计算的结果分析 6)时间与空间代价分析 假设状态空间树有n层 时间复杂度: 最坏情况为: 深度优先: 2^n 广度优先: 2^n 空间开销主要为存储前驱位置信息的开销 7)有待改进的问题,收获和体会 广度优先用于求特解,深度优先(回溯)用于求特解与通解 算法题: 迷宫问题 解题思路: 递归求解迷宫问题: 首先画出状态空间树,给出四种基本移位的表示。 每一个状态可以用横坐标x与纵坐标y来表示,移位操作用L[i],R[i],两个数组来存放,其中1表示对应坐标+1,0 表示对应坐标不变。 采用待回溯的深度优先遍历,当输出全解时,只需要在满足到达终点的条件下不进行任何操作,输出特解时为写上return 非递归求解迷宫问题: 首先实现栈的基本操作,栈中的数据部分类型声明为(x,y,d),其中x,y表示当前的位置信息,d记录执行的操作数。 建立一个空栈,将初始值压入栈中,当栈内元素不为空时,取栈顶元素,为取出的栈节点赋值给x,y,i,当当前操作数i的值小于4时, 则首先1: 判断当前节点是否为最后一个节点,如果是,就输出;再判断2: 执行当前操作得到的下一个节点是否可靠,如果是则讲下一个节点的信息压入栈中(初试操作数d置为0) 3: 其他情况就将它的操作数自加一。 否则就将当前节点的值修改为0,弹栈,栈顶元素的操作数加1,直到循环结束。 全解与特解的区别在于特解在输出一个解后就自动跳出。 源代码(有输入输出,可以运行) 输入: 由input.txt文件输入 代码: //头文件head.h #ifndefhead_h #definehead_h #include #include #include #include"stdlib.h" usingnamespacestd; typedefstruct { intx,y,d; }Datatype; structseqstack//栈 { intMAXMUM; intt;//指向栈顶 Datatype*s; }; typedefseqstack*pseqstack;//顺序栈类型的指针类型 pseqstackcreateEmpty_seq(intm);//创建一个空栈 intisempty(pseqstackpastack);//判断是否为空栈 voidpush_seq(pseqstackpastack,intx1,inty1,intd1);//进栈运算,压栈 voidpop_seq(pseqstackpastack);//出栈,弹栈 Datatypetop_seq(pseqstackpastack);//取栈顶元素 voidshow(pseqstackpstack);//输出栈元素,按取栈操作顺序 voidfreemo(pseqstackpstack);//释放栈内存 #endif //head.cpp文件 #include"head.h" pseqstackcreateEmpty_seq(intm)//创建一个空栈 { pseqstackpalist=(pseqstack)malloc(sizeof(structseqstack)); if(palist! =NULL) { palist->s=(Datatype*)malloc(sizeof(Datatype)*m); if(palist->s) { palist->MAXMUM=m; palist->t=-1;//栈顶指向-1,表示空栈 returnpalist; } elsefree(palist); } printf("outofspace! ! \n"); returnNULL; } intisempty(pseqstackpastack)//判断是否为空栈 { returnpastack->t==-1; } voidpush_seq(pseqstackpastack,intx1,inty1,intd1)//进栈运算,压栈 { if(pastack==NULL) { printf("栈地址无效\n"); return; } if(pastack->t>=pastack->MAXMUM-1) { printf("shangOVERFLOW! \n"); return; } else{ pastack->t=pastack->t+1;//栈顶位置上移 pastack->s[pastack->t].x=x1;//赋值 pastack->s[pastack->t].y=y1;//赋值 pastack->s[pastack->t].d=d1;//赋值 } } voidpop_seq(pseqstackpastack)//出栈,弹栈 {if(pastack==NULL) { printf("栈地址无效\n"); return; } if(pastack->t==-1)//已经空栈 { printf("xiaOVERFLOW! \n"); return; } else { pastack->t=pastack->t-1;//下移动栈顶指针 } } Datatypetop_seq(pseqstackpastack)//取栈顶元素 {Datatypes1; s1.x=0; s1.y=0; s1.d=-1; if(pastack==NULL) { printf("栈地址无效\n"); returns1; } if(pastack->t==-1)//已经空栈 { printf("已经是空栈\n"); returns1; } else { returnpastack->s[pastack->t];//返回栈顶指针对应的值 } } voidshow(pseqstackpstack)//输出栈元素,按取栈操作顺序 { if(pstack==NULL) { printf("栈地址无效\n"); return; } if(pstack->t==-1)//已经空栈 { printf("已经是空栈\n"); return; } intm=pstack->t; printf("结果为: "); for(inti=0;i<=m;i++) printf("(%d,%d)->",pstack->s[i].x,pstack->s[i].y); printf("\n"); } voidfreemo(pseqstackpstack)//释放栈内存 { if(pstack==NULL) { printf("栈地址无效\n"); return; } free(pstack->s); free(pstack); } //主程序main.cpp文件 #include"head.h" //L[i]与r[i]代表迷宫的走法 intL[4]={1,0,-1,0}; intR[4]={0,1,0,-1}; int**a,n,m; int*F;//记录路径x坐标 int*Q;//记录路径y坐标 //判断(x,y)为有效的步骤,即当前的值为0, boolpanduan(intx,inty) { returna[x][y]==0; } //递归实现求全解 voiddigui_migong(intx,inty,intk) { if(a[n][m]! =0) { for(inti=1;i<=n;i++) { for(intj=1;j<=m;j++) printf("%d",a[i][j]); printf("\n"); } printf("The
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 上机 报告