本文主要是介绍算法设计与分析实验报告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、编写一个生命游戏
2、带锁的门
3、三壶谜题
4、串匹配
复杂度最坏情况O(M*N)(M,N分别为2个字符串的长度)。
5、交替放置的碟子
这篇关于算法设计与分析实验报告c++实现(生命游戏、带锁的门、三壶谜题、串匹配问题、交替放置的碟子)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!