算法设计与分析实验报告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

相关文章

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

SpringSecurity整合redission序列化问题小结(最新整理)

《SpringSecurity整合redission序列化问题小结(最新整理)》文章详解SpringSecurity整合Redisson时的序列化问题,指出需排除官方Jackson依赖,通过自定义反序... 目录1. 前言2. Redission配置2.1 RedissonProperties2.2 Red

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.

nginx 负载均衡配置及如何解决重复登录问题

《nginx负载均衡配置及如何解决重复登录问题》文章详解Nginx源码安装与Docker部署,介绍四层/七层代理区别及负载均衡策略,通过ip_hash解决重复登录问题,对nginx负载均衡配置及如何... 目录一:源码安装:1.配置编译参数2.编译3.编译安装 二,四层代理和七层代理区别1.二者混合使用举例

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控