算法设计与分析实验报告c++实现(生命游戏、带锁的门、三壶谜题、串匹配问题、交替放置的碟子)

本文主要是介绍算法设计与分析实验报告c++实现(生命游戏、带锁的门、三壶谜题、串匹配问题、交替放置的碟子),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、实验目的

1.加深学生对分治法算法设计方法的基本思想、基本步骤、基本方法的理解与掌握;
2.提高学生利用课堂所学知识解决实际问题的能力;
3.提高学生综合应用所学知识解决实际问题的能力。

二、实验任务

1、 编写一个生命游戏:
规则如下:(或者网上找到更详细的规则)
一个人可以有8个邻居;
一个人若只有一个邻居,在下一代会孤独的死去;
若有2或3个邻居,在下一代依然活着;
若有4个或以上邻居,在下一代会因拥挤而死;
死去的人若有3个邻居,在下一代会复活;
所有的死去或复活都在下一代变化时同时发生。
2、 带锁的门:
在走廊上有n个带锁的门,从1到n依次编号。最初所有的门都是关着的。我们从门前经过n次,每次都从1号门开始。在第i次经过时(i = 1,2,…, n)我们改变i的整数倍号锁的状态;如果门是关的,就打开它;如果门是打开的,就关上它。在最后一次经过后,哪些门是打开的,哪些门是关上的?有多少打开的门?
3、三壶谜题:
有一个充满水的8品脱的水壶和两个空水壶(容积分别是5品脱和3品脱)。通过将水壶完全倒满水和将水壶的水完全倒空这两种方式,在其中的一个水壶中得到4品脱的水。
4、串匹配问题
给定一段文本,在该文本中查找并定位任意给定字符串。
要求:
(1)实现BF算法;(必做)
(2) 实现BF算法的改进算法:KMP算法和BM算法;(选做)
5、交替放置的碟子
我们有数量为2n的一排碟子,n黑n白交替放置:黑,白,黑,白…
现在要把黑碟子都放在右边,白碟子都放在左边,但只允许通过互换相邻碟子的位置来实现。为该谜题写个算法,并确定该算法需要执行的换位次数。

三、实验设备及编程开发工具

笔记本,Windows10操作系统,Dev-C++

四、实验过程设计(算法设计过程)

1、编写一个生命游戏

(1)问题分析:
解法生命游戏的规则可简化为以下,并使用CASE比对即可使用程式实作:
邻居个数为0、1、4、5、6、7、8时,则该细胞下次状态为死亡。
邻居个数为2时,则该细胞下次状态为复活。
邻居个数为3时,则该细胞下次状态为稳定。
代码是不断生成细胞存活的状态图,首先细胞默认都是死的,活细胞需要你自己一个一个生成,核心代码在neighbors(int,int)函数里面。

(2)算法实现

//需要的头文件以及宏定义,最多8*8个人,存活状态为1,死亡状态为0
#include<stdio.h>
#define MAXROW 8 
#define MAXCOL 8
#define ALIVE 1
#define DEAD 0
//函数声明
int map[MAXROW][MAXCOL], newmap[MAXROW][MAXCOL];
void init();//初始化游戏
int neighbors(int, int);//根据邻居数量判定生命状态
void outputMap()//输出游戏当代的状态
void copyMap();//复制当代的状态
//主函数
int main()
{int row, col;char ans;init();while (1){outputMap();for (row = 0; row < MAXROW; row++){for (col = 0; col < MAXCOL; col++){switch (neighbors(row, col)){case 0:case 1:case 4:case 5:case 6:case 7:case 8:newmap[row][col] = DEAD;break;case 2:newmap[row][col] = map[row][col];break;case 3:newmap[row][col] = ALIVE;break;}}}copyMap();printf("\nContinue next Generation ? ");getchar();ans = toupper(getchar());if (ans != 'Y')break;}return 0;
}
//生命游戏初始化,由用户输入存活人的坐标x,y,按-1,-1结束
void init()
{int row, col;for (row = 0; row < MAXROW; row++)for (col = 0; col < MAXCOL; col++)map[row][col] = DEAD;puts("Game of life Program");puts("Enter x, y where x, y is living cell");printf("0 <= x <= %d, 0 <= y <= %d\n", MAXROW - 1, MAXCOL - 1);puts("Terminate with x, y = -1, -1");while (1){scanf("%d%d", &row, &col);if (0 <= row && row < MAXROW && 0 <= col && col < MAXCOL)map[row][col] = ALIVE;else if (row ==  - 1 || col ==  - 1)break;elseprintf("(x, y) exceeds map ranage!");}
}//游戏规则制定,根据邻居数量判定人的生命状态,row,col为人的坐标
int neighbors(int row, int col)
{int count = 0, c, r;for (r = row - 1; r <= row + 1; r++)for (c = col - 1; c <= col + 1; c++){if (r < 0 || r >= MAXROW || c < 0 || c >= MAXCOL)continue;if (map[r][c] == ALIVE)count++;}if (map[row][col] == ALIVE)count--;return count;
}
//打印游戏状态,死亡记为“_”,生存记为“*”
void outputMap()
{int row, col;printf("\n\n%20cGame of life cell status\n");for (row = 0; row < MAXROW; row++){printf("\n%20c", ' ');for (col = 0; col < MAXCOL; col++)if (map[row][col] == ALIVE)putchar('*');elseputchar('-');}
}void copyMap()
{int row, col;for (row = 0; row < MAXROW; row++)for (col = 0; col < MAXCOL; col++)map[row][col] = newmap[row][col];
}

2、带锁的门

(1)问题分析:
举例说明:假设n = 5,0表示门是关着的,1表示门是开着的,则模拟上述过程如下:
状态数组下标:1 2 3 4 5
状态数组的值:0 0 0 0 0 ―――>初始状态
状态数组的值:1 1 1 1 1 ―――>第一次
状态数组的值:1 0 1 0 1 ―――>第二次
状态数组的值:1 0 0 0 1 ―――>第三次
状态数组的值:1 0 0 1 1 ―――>第四次
状态数组的值:1 0 0 1 0 ―――>第五次
(2)算法实现

//需要的头文件以及宏定义,N为门数量的最大值
#include <stdio.h>
#define N 1000
//主函数
int main()
{int L[N];int i,j,k;int n;printf("请输入小于1000的整数代表门的总数:");while(1){scanf("%d",&n);if(n<0||n>1000)//验证输入是否在有效范围内printf("输入错误,请重新输入");else break;}for(i=0;i<n;i++)L[i]=0;for(j=1;j<=n;j++)for(k=1;k<=n;k++)if(k%j==0)L[k-1]=(L[k-1]+1)%2;for(i=0;i<n;i++){if(L[i]==1)printf("第%d号门开着\n",i+1);}
printf("\n");
return 0;     
}

3、 三壶谜题

(1) 问题分析:
可以把每次三个水壶中水的量组成一个状态,比如初始状态为008,对应第一个水壶0品脱水,第二个水壶0品脱水,第三个水壶8品脱水。对题目的状态空间图进行广度优先遍历。当表示状态的数字中出现4时,即求出答案。
1、为了打印出倒水的过程,需要声明一个前置状态保存当前状态由哪个状态转换而来,然后就可以回溯到初始状态,打印出倒水过程。相当于树中的父结点。
2、可以声明一个map表,保存已有的状态,对已有的状态,就不再向下继续遍历,这样可以节省求解时间。
3、因为是广度优先遍历,所以第一次解得的答案所需的倒水的次数最少,解为最优解。

(2) 算法实现

#include <iostream>
#include <vector>
#include <map>
#define MaxFirst 3
#define MaxSecond 5
#define MaxThird 8
using namespace std;class State
{
public:int second;int num[3];State* preState;static map<int,int> mapping;public:State(int first,int second,int third){num[0]=first;num[1]=second;num[2]=third;	}void init(){		mapping[0]=MaxFirst;mapping[1]=MaxSecond;mapping[2]=MaxThird;}bool canPour(int from,int to)//判断是否可以从from水壶中倒水到to水壶中{if(num[from]==0){return false;}if(num[to]==mapping[to]){return false;}else {return true;}}void pour(int from,int to)//倒水过程{if(num[from]+num[to]>mapping[to]){num[from]=num[from]-(mapping[to]-num[to]);num[to]=mapping[to];}else{num[to]=num[to]+num[from];num[from]=0;}}};
map<int,int> State::mapping;int main()
{map<int,int> states;State *start=new State(0,0,8);start->init();State *state=start;State *endState=new State(8,8,8);//只有获得解endState才会改变,赋值全为8为了方便判断是否获得最终解vector<State> action;//保存所有状态对象action.push_back(*start);//把初始状态先加入队列中int n=0;do{for(int i=0;i<3;i++)//双层循环为从i水壶中倒水入j水壶中{for(int j=0;j<3;j++){if(i!=j){if(state->canPour(i,j)){state->pour(i,j);if(states[state->num[0]*100+state->num[1]*10+state->num[2]]==0)//如果该状态不在hash表中,即为第一次出现该状态{states[state->num[0]*100+state->num[1]*10+state->num[2]]++;(state->preState)=new State(action[n]);action.push_back(*state);if(state->num[0]==4||state->num[1]==4||state->num[2]==4)//获得解{endState=state;i=4;break;	}}}}*state=action[n];}			}n++;}while(endState->num[0]==8&&endState->num[1]==8&& n<action.size());cout<<endState->num[0]<<" "<<endState->num[1]<<" "<<endState->num[2]<<endl;state=endState;do{state=state->preState;cout<<state->num[0]<<" "<<state->num[1]<<" "<<state->num[2]<<endl;		}while(state->num[2]!=8);return 0;
}

4、 串匹配问题

(1) 问题分析
从主串s的pos位置出发,与子串t第一位进行匹配,若相等,接着匹配后一位字符,若不相等,则返回到s前一次匹配位置的后一位,接着与t的起始位进行匹配,直到与t全部匹配成功,则返回在s中开始完全匹配的下标。
简单说这个算法的思想就是匹配失败,就重新从上一次匹配位置的下一位开始匹配。

(2) 算法实现

#include <stdio.h>          //头文件
#include <string.h>        //字符串头文件//BF算法 s是原字符串,t是匹配字符串
int BF(char s[],char t[],int pos)
{int m,n;int i=pos,j=0;          //从0位置开始匹配m=strlen(s);n=strlen(t);             //用m,n表示s,t长度while (i<=m&&j<=n)       //m,n是串长{if (s[i]==t[j]){i++;  j++;        //逐个匹配,成功s++   t++} else{i=i-j+1;       //不成功,s返回到此次循环匹配的初始位置j=0;           //不成功,t返回到0位置}  }if(j>n)return (i-n);          //返回匹配成功的原串中第一个字符的位置  elsereturn 0;}int main(){char s[]="abcdeabcabcde";      //初始定义s串int pos;pos=BF(s,"abcd",0);        //从0位置匹配abcdprintf("pos=%d\n",pos);pos=BF(s,"abcde",pos);    //从上次匹配成功的位置匹配abcdeprintf("pos=%d\n",pos);return 0;
}

5、 交替放置的碟子
(1) 问题分析
输入盘子总数2n,起始状态黑白盘子交替出现,为黑白黑白黑白…定义黑为2,白为1,则初始状态利用数组存储为[2,1,2,1,2,1…],对数组内的数据进行排序将所有的1放置所有的2之前,输出为[2,2,2,1,1,1…]即可实现。
(2) 算法实现

#include<stdio.h>int main(){int bubble_num,i ;void sortDisplay(int bubble_set[],int length);printf("请输入盘子总数:");	scanf("%d",&bubble_num);printf("\n");int bubble_set[bubble_num];int length = sizeof(bubble_set)/sizeof(bubble_set[0]);for(i=0;i<=(length-2)/2;i++){bubble_set[2*i]=2;bubble_set[2*i+1]=1;}printf("盘子的初始顺序为:\n");	sortDisplay(bubble_set,length);printf("\n");for(i=0;i<length-1;i++){int j; for(j=0;j<length-1-i;j++){if(bubble_set[j+1]<bubble_set[j]){int t=bubble_set[j];bubble_set[j]=bubble_set[j+1];bubble_set[j+1]=t;}}}printf("盘子排序后的顺序为:\n");sortDisplay(bubble_set,length);return 0;
}void sortDisplay(int bubble_set[],int length){int i; for(i=0;i<length;i++){
//			printf("%d ",bubble_set[i]); if(bubble_set[i]==1){printf("白 ");}else{printf("黑 ");;}}printf("\n");
}

五、实验结果及算法复杂度分析
1、编写一个生命游戏

img

2、带锁的门

img

3、三壶谜题

img

4、串匹配

image-20240404122431379

复杂度最坏情况O(M*N)(M,N分别为2个字符串的长度)。
5、交替放置的碟子

image-20240404122751386

这篇关于算法设计与分析实验报告c++实现(生命游戏、带锁的门、三壶谜题、串匹配问题、交替放置的碟子)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/903282

相关文章

linux生产者,消费者问题

pthread_cond_wait() :用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。 pthread_cond_wait() 必须与pthread_mutex 配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

2024.6.24 IDEA中文乱码问题(服务器 控制台 TOMcat)实测已解决

1.问题产生原因: 1.文件编码不一致:如果文件的编码方式与IDEA设置的编码方式不一致,就会产生乱码。确保文件和IDEA使用相同的编码,通常是UTF-8。2.IDEA设置问题:检查IDEA的全局编码设置和项目编码设置是否正确。3.终端或控制台编码问题:如果你在终端或控制台看到乱码,可能是终端的编码设置问题。确保终端使用的是支持你的文件的编码方式。 2.解决方案: 1.File -> S

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

vcpkg安装opencv中的特殊问题记录(无法找到opencv_corexd.dll)

我是按照网上的vcpkg安装opencv方法进行的(比如这篇:从0开始在visual studio上安装opencv(超详细,针对小白)),但是中间出现了一些别人没有遇到的问题,虽然原因没有找到,但是本人给出一些暂时的解决办法: 问题1: 我在安装库命令行使用的是 .\vcpkg.exe install opencv 我的电脑是x64,vcpkg在这条命令后默认下载的也是opencv2:x6