赞
踩
1 实验目的
(1)灵活掌握控制结构及其逻辑特点,学会逐步求精的算法设计。
(2)学习如何把逻辑结构相同的部分抽象为函数,以提高代码的可重用性,
达到提高程序的可维护性的目的。
(3)学习使用数组作为函数参数的方法。
2 实验内容
2.1 打印温度柱状图
(1)问题描述
下图是某城市 15 天的气温变化曲线。其中标注为 A 的地方称为峰点,标记
为 B 的地方称为谷点,而标记为 C 的地方称为崮。要求编写 1 个函数输入 15 天
的气温,然后通过 3 个函数分别实现下述功能:
(1)打印每天温度的柱状图(仅考虑温度为正值的情况)。
(2)打印所有峰点的位置(该月的第几天)及峰值。如果没有,则打印没
有峰值。
(3)打印最长的崮的长度。只使用一重循环即可求出。
(2)问题要求
请实现以下函数声明,要求能得到如下图所示的运行结果。
源代码
/*********************************************** 文件名:WeatherForecast.cpp 概要: 模拟天气预报,一个月的温度分析 函数: 1. displayTemp,显示月间温度的柱状图 2. displayPeaks,显示月间温度中的峰值 3. displayFlat,显示月间持续最久的温度 4. forecasting,接收用户输入, 调用上面的3个函数 ************************************************/ #include <iostream> #include <iomanip> using namespace std; int minTemp(int temp[], int n) { int min = temp[0]; for (int i = 1; i < n; i++) { if (min > temp[i]) min = temp[i]; } return min; } // 显示柱状图 void displayTemp(int temp[], int n) { int min = minTemp(temp, n); // 先求出最低温度 for (int i = 0; i < n; i++) { if (min < 0) {// 存在零下温度的时候,最低温度小于零 cout << setw(4) << temp[i] << " "; if (temp[i] < 0) { for (int j = 0; j < temp[i] - min; j++) cout << " "; for (int k = temp[i]; k < 0; k++) cout << "*"; cout << "|" << endl; } else { for (int j = min; j < 0; j++) cout << " "; cout << "|"; for (int k = 0; k < temp[i]; k++) cout << "*"; cout << endl; } } else { // 不存在零下温度的时候 cout << setw(4) << temp[i] << " |"; for (int j = 0; j < temp[i]; j++) cout << "*"; cout << endl; } } } // 显示月间温度中的峰值 void displayPeaks(int temp[], int n) { bool flag = false; for (int i = 1; i < n - 1; i++) { if (temp[i - 1] < temp[i] && temp[i] > temp[i + 1]) { flag = true; cout << "Peak at day " << i + 1 << " is " << temp[i] << endl; } } if (!flag) cout << "No peaks." << endl; } // 显示月间持续最久的温度 void displayFlat(int temp[], int n) { int length = 1; int maxLength = 0; for (int i = 1; i < n; i++) { if (temp[i - 1] == temp[i]) length++; else { if (length > maxLength) maxLength = length; length = 1; } } // 处理最长崮在最后的情况 if (length > maxLength) maxLength = length; cout << "The length of longest flat is " << maxLength << endl; } int main() { int temp[15]; // 存储 15 天的温度 cout << "Please input the tempratures:\n"; // 输入 15 天的温度 for (int i = 0; i < 15; i++) cin >> temp[i]; cout << "\n显示柱状图如下:\n"; displayTemp(temp, 15); // 显示柱状图 cout << "\n显示峰值如下:\n"; displayPeaks(temp, 15); // 求出所有的峰值温度 cout << "\n显示崮的长度如下:\n"; displayFlat(temp, 15); // 求出持续时间最长的温度 return 0; }
2.2 滑动积木块游戏
(1)问题描述
滑动积木块游戏的棋盘结构及某一种将牌的初始排列结构如图所示。
其中,B 表示黑色将牌,W 表示白色将牌,E 表示空格。我们称将牌的排列
结构称为格局,而根据单色将牌的个数,将游戏分别称为 3 滑块或 4 滑块游戏等。
所以,上图就是 3 滑块游戏的初始格局。我们可以用字符串来代表格局,代表上
图中初始格局的字符串为 BBBWWWE。
游戏的规定走法是:
(1)任意一个将牌可以移入相邻的空格;
(2)任意一个将牌可相隔 1 个或 2 个其他的将牌跳入空格。
游戏要达到的目标是使所有白将牌都处在黑将牌的左边(左边有无空格均可),我们称为目标格局。很显然,3 滑块游戏的目标格局共有 7 种。
随着将牌的移动,我们会得到一些中间格局,例如:
对于某个格局,通过一次移动滑块而得到的格局,称为其后继格局。我们需
要找到某个中间格局的所有后继格局,即每种可能的走法所能得到的格局。
(2)输入
输入的第一行是一个整数 N,表示共有 N 个格局。后续紧跟 N 行,每行由
两部分构成,第一部分是一个整数 n,表示这是一个 n 滑块游戏,第二部分是 2n+1
个字符,表示该游戏的某个格局。
(3)输出
首先判断输入的格局是否是目标格局,如果是,则输出“目标格局”后结束;
4
如果不是目标格局,则按顺序(将格局看作字符串后,按照字典序排序,即
B < E < W)输出该格局的所有后继格局。例如,BBEBWWW 格局应该排在
BBWBWEW 格局的前面,因为在英文字母表中,第一个格局中的第 3 个字符 E
排在第二个格局的第 3 个字符 W 前面
(4)示例
输入
2
3 BBWBEWW
4 WWWWBBEBB
输出
结果_1
BBEBWWW
BBWBWEW
BBWBWWE
BBWEBWW
BEWBBWW
结果_2
目标格局
题目分析
题目中没有说明输入的格局数N
的范围,也没有说明每个格局的最大长度,为了简化代码,我们假设输入的格局数不超过6,每个格局的长度不超过20个字符。将所有输入的格局存储到二维数组buffer
中,其定义如下
const int MAX_N = 6;//输入的最大格局数
const int MAX_LEN = 20;//每个格局的最大长度
char buffer[MAX_N][MAX_LEN];
待全部格局都输入到buffer
中之后,对每个格局进行遍历。首先判断当前遍历到的格局是否为目标格局,这个判断相对来说是比较容易的,可以通过找最后一个W
的位置wMaxIndex
和第一个B
的位置bMinIndex
来判断。如果满足wMaxIndex < bMinIndex
,那么此格局为目标格局。举个例子,比如说下面的这个格局。
BBWBEWW
最后一个W
的位置wMaxIndex
是6(从0开始),第一个B
的位置bMinIndex
是0。不满足上式,因此不是目标格局。
再看另一个格局。
WWWWBBEBB
最后一个W
的位置wMaxIndex
是3,第一个B
的位置bMinIndex
是4,满足wMaxIndex < bMinIndex
,因此它是目标格局。
若不是目标格局,后面就需要找它的后继格局。首先找到E
所在的位置,根据题目要求,E
之前的三个将牌都可以和E
进行交换,E
之后的三个将牌也可以和E
交换。现在的问题是,E
之前或之后是否有三个将牌?因此在交换之前,需要先判断一下是否越界。比如下面这个格局。
BBWBEWW
E
的位置index
为4,它可以与第index+1
个将牌交换,可以与第index+2
个将牌交换,但是不能与第index+3
个将牌交换,因为index+3
已经越界了。
将所有的后继格局存储下来,在输出之前按照题目要求进行排序即可。
源代码
#include<iostream> #include<cstring> using namespace std; //将数组str中的第i个元素和第j个元素互换 void swap(char str[], int i, int j) { char ch = str[i]; str[i] = str[j]; str[j] = ch; } //将result数组的前counter个进行冒泡排序,看不懂也没关系,只要知道函数的功能就行 void bubbleSort(char result[][20], int counter, int length) { char str[20]; for (int i = counter - 1; i > 0; i--) for (int j = 0; j < i - 1; j++) if (strcmp(result[j + 1], result[j]) < 0) { strcpy(str, result[j]); strcpy(result[j], result[j + 1]); strcpy(result[j + 1], str); } } //判断sliders是否为目标格局 bool check(char* sliders,int length) { int wMaxIndex = 0;//最后一个白色将牌的下标 int bMinIndex = 0;//第一个黑色将牌的下标 for (int i = 0; i < length; i++) { if (sliders[i] == 'W') wMaxIndex = i; else if (sliders[i] == 'B') bMinIndex = i; } if (wMaxIndex < bMinIndex) return true; return false; } int main() { //假设输入的最大格局数是6,每个格局的最大长度是20 const int MAX_N = 6;//输入的最大格局数 const int MAX_LEN = 20;//每个格局的最大长度 char buffer[MAX_N][MAX_LEN];//假设输入的格局不超过6个,每个格局不超过20个字符。 int N; cin >> N; for (int i = 0; i < N; i++) { int numSlider; cin >> numSlider; cin >> buffer[i]; } for (int k = 0; k < N; k++) {//对每一个格局进行遍历处理 int counter = 0;//记录该格局的后继格局数 int length = strlen(buffer[k]);//length是当前格局的长度 char sliders[20]; char result[10][20];//存放该格局的所有后继格局,假设不超过10个 cout << "结果_" << k + 1 << endl; strcpy(sliders, buffer[k]);//将当前格局复制到sliders中 if (check(sliders,length)) {//检查当前格局是否为目标格局 cout << "目标格局" << endl; continue; } for (int i = 0; i < 10; i++) {//将当前格局复制到二维数组result的每一维上 strcpy(result[i], sliders); } int index = 0; for (; index < length; index++) { // 查找空格字符E的下标 if (sliders[index] == 'E') break; } for (int offset = 1; offset < 4; offset++) { if (index + offset < length) { swap(result[counter], index, index + offset);//将空格和它右边的将牌交换 counter++; } if (index - offset >= 0) { swap(result[counter], index, index - offset);//将空格和它左边的将牌交换 counter++; } } bubbleSort(result, counter, length);//对当前格局的所有后继格局按照题目要求进行排序 for (int m = 0; m < counter; m++)//输出当前格局的所有后继格局 cout << result[m] << endl; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。