模拟类题目是机试题中出现频率很高的一种类型,这类题目的特点是并不涉及特别高 深的知识,只需利用程序实现题目的要求。由于这类题目通常不需要经过太多的思考,所以能够很纯粹地考查考生的编程能力。
1. 图形排版
图形排版是最为常见的模拟类题型,这类题目要求考生按照特定规则输出字符,主要考查考生对输出格式的把握。通常来说这类题目的规律性比较强,掌握了题目中的规律,题目便能迎刃而解。
解法一:
思路:其实这类题目就是去例举几个特殊的例子,然后通过观察找出其中的规律
第一步:每一行字符的总数为h+(h-1)*2,得出这个式子
第二步:找出每一行*字符与高h和i之间的关系
第三步:利用总数减去每一行*字符的个数,就得出空格的个数
采用的方式是逐行进行输出的方式
#include<iostream>
using namespace std;
int main()
{int h = 0;while (cin >> h){for (int i = 0; i < h; i++)//一共h层{for (int j = 0; j < 2 * h - 2 * i - 2; j++){cout << " ";}//利用第一个for循环输出空格for (int j = 0; j < h + 2 * i; j++){cout << "*";}//利用第二个for循环输出*cout << endl;//每输出一行要输出一个换行符}}return 0;
}
运行结果:
解法二:(利用二维数组处理图案模拟问题)
思路:
step1:先申请足够大小的二维数组,放在全局变量的位置
step2:根据题目条件,从任意方向开始,设置二维数组的初始值,此题就是空格
step3:注意将二维数组的每一行的边界的最后一个位置使用\0赋值
step4:进行字符串的输出
#include<iostream>
using namespace std;char arr[1000][3000];//此处将arr数组定义在全局中,存放在静态区
int main()
{int h = 0;while (cin >> h){//step1:用空格填充每一个位置元素for (int i = 0; i < h; i++)//一共h层{for (int j = 0; j < 3 * h - 2; j++)//每一行的元素总数{arr[i][j] = ' ';//注意这个地方要用单引号,双引号表示的是字符串,char类型是用单引号}arr[i][3 * h - 2] = '\0';//二维数组的每一行结尾用\0标识结束}//step2:填上*号,从上到小找规律进行赋值for (int i = 0; i < h; i++){for (int j = 2 * h - 2 * i - 2; j < 3 * h - 2; j++)//这里j的初值需要列表进行找出规律{arr[i][j] = '*';}}//step3:输出每行结果for (int i = 0; i < h; i++){cout << arr[i];//这里的arr[i]表示的是一行的字符串cout << endl;//换行}}return 0;
}
题目2:叠筐__牛客网 (nowcoder.com)https://www.nowcoder.com/questionTerminal/2d6505bf0d38479c9bff66e10fe39a5c
思路:
题解:
#include<iostream>
using namespace std;int main()
{char inner, outer;int n;char arr[80][80] = { 0 };//把每个位置元素初始化为字符0while (cin >> n >> inner >> outer){int length;//length表示每一层正方形边框的长度int x, y;//x,y表示坐标char curimage = inner;//表示此次需要赋值的图案for (length = 1, x = n / 2, y = n / 2; length <= n; length += 2, x--, y--){//起始时正方形长度为1,每一次边框长度增加2,当长度增加到n时结束//x,y分别为起始时的坐标,从最中间元素开始,沿着对角线从开始移动for (int i = x, j = y; i < x + length; i++)//先循环打印竖着的一列{//j表示列,j不变,i从x到x+length-1依次增加arr[i][j] = curimage;}for (int i = x, j = y; j < y + length; j++)//先循环打印横着的一行{//i表示行,i不变,j从y到y+length-1依次增加arr[i][j] = curimage;}for (int i = x, j = y + length - 1; i < x + length; i++){//j表示列,j不变,i从x到x+length-1依次增加arr[i][j] = curimage;}for (int i = x + length - 1, j = y; j < y + length; j++){//i表示行,i不变,j从y到y+length-1依次增加arr[i][j] = curimage;}//每一次打印完一个边框正方形需要更换图案if (curimage == inner){curimage = outer;}else{curimage = inner;}}//挖去四个角if (n != 1){arr[0][0] = ' ';arr[0][n - 1] = ' ';arr[n - 1][0] = ' ';arr[n - 1][n - 1] = ' ';}//输出for (int i = 0; i < n; i++){cout << arr[i] << endl;}//注意题目要求,叠框与叠框之间有一行间隔cout << endl;}return 0;
}
通过此题,补充几个常见的OJ刷题过程中会遇到的错误:
2.日期问题
日期类运算的各种问题同样被频繁地选入机试考题中,但这类问题通常都有规律可循。只要能够把握这类问题题面中的核心规律,求解这类问题就不会有太大的难度。
解决日期类问题之前,要有一个对于闰年的常识,闰年应该怎么判断:
1.当年份可以被4整除但不能被100整除时,
2.或者可以被400整除时,就是闰年。
题目一:今年的第几天?_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/ae7e58fe24b14d1386e13e7d70eaf04d?tpId=40&tqId=21350&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking
#include<iostream>
using namespace std;int main()
{int monthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//将每月有多少天用一个数组存起来//这里有一个技巧,第一个位置多存了一个0,方便后面的月份可以直接对应到数组的下标int year, month, day;while (cin >> year >> month >> day){int count = 0;//计算是第几天//判断输入的年份是否是闰年if ((year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0)){monthDay[2] = 29;//是闰年,二月份为28天}else{monthDay[2] = 28;}for (int i = 1; i < month; i++){count += monthDay[i];}//若是5月1号,那么累加出1到4月的总天数count += day;//最后再累加上day天数cout << count << endl;}return 0;
}
题目二:
打印日期_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/b1f7a77416194fd3abd63737cdfcf82b?tpId=69&tqId=29669&tPage=1&ru=/kaoyan/retest/11002&qru=/ta/hust-kaoyan/question-ranking解法:
#include<iostream>
using namespace std;
int main()
{int monthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//将每月有多少天用一个数组存起来//这里有一个技巧,第一个位置多存了一个0,方便后面的月份可以直接对应到数组的下标int year, day;int month = 1;//给定初值month为1while (cin >> year >> day){//判断输入的年份是否是闰年if ((year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0)){monthDay[2] = 29;//是闰年,二月份为28天}else{monthDay[2] = 28;}while (day > monthDay[month])//如果day超过的当月的天数,则继续迭代{day -= monthDay[month];month++;if (month == 13){year++;month = 1;}}printf("%04d-%02d-%02d\n", year, month, day);//注意打印的问题}return 0;
}
通过此题注意一下输入的问题:
题目三:
Day of Week_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/a3417270d1c0421587a60b93cdacbca0?tpId=40&tqId=21439&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking
翻译一下此题:
描述:我们现在在俄罗斯使用公历方式来计算日期。闰年是指能被4整除但不能被100整除的年份,或者能被400整除的年份。例如,2004年、2180年和2400年是闰年,而2005年、2181年和2300年不是闰年。你的任务是编写一个程序,根据今天关于日期的约定,计算给定日期最近的过去或未来的星期几。输入描述:有一行文字包含了日期数字d、月份名称M和年份y(1000≤y≤3000)。月份名称用对应的英文名称,首字母大写。
输出描述:请输出一行,其中包含与日期对应的星期几的英文名称,首字母大写。所有其他字母必须是小写。输入/输出中的月份和星期名称:一月、二月、三月、四月、五月、六月、七月、八月、九月、十月、十一月、十二月,星期日、星期一、星期二、星期三、星期四、星期五、星期六。
思路:
C++的字符串操作更方便,下面来看C++中字符串的使用:
map也是C++中的语法,通过map可以非常方便的完成映射的关系对应
解析:
#include<iostream>
#include<string>
#include<map>
using namespace std;int main()
{int day, year;int monDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };string MonthName;//键 key 值 valuemap<string,int> String_to_int={{"January", 1},{"February",2},{ "March",3},{"April",4},{"May",5},{"June",6},{"July",7},{"August",8},{"September",9},{"October",10},{"November",11},{"December",12}};while (cin >> day >> MonthName >> year){int month = String_to_int[MonthName];//将字符串的月份转为数字的月份//用flag标志位判断是现在还是未来的日子int flag = 0;if ((year > 2024)|| ((year == 2024) && (month > 1))|| ((year == 2024) && (month == 1) && (day > 25))){flag = 0;//说明是未来的日子}else{flag = 1;//说明是之前的日子}int begyear, begmonth, begday, endyear, endmonth, endday;if (flag == 0){//说明是未来的日子begyear = 2024;begmonth = 1;begday = 25;endyear = year;endmonth = month;endday = day;}else{//说明是之前的日子begyear = year;begmonth = month;begday = day;endyear = 2024;endmonth = 1;endday = 25;}int count = 0;while (true){if (begyear == endyear && begmonth == endmonth && begday == endday){//说明找到相等的然后退出循环break;}count++;//相差的天数+1//判断输入的年份是否是闰年//注意这一步非常容易错,判断这个闰年一定要放在这个循环之中,因为每一次循环时,year都在变if ((begyear % 400 == 0) || ((begyear % 4 == 0) && (begyear % 100 != 0))){monDay[2] = 29;//是闰年,二月份为28天}else{monDay[2] = 28;}begday++;if (begday > monDay[begmonth])//利用nextDay的思路去计算相差多少天{begmonth++;begday = 1;if (begmonth == 13){begyear++;begmonth = 1;}}}//通过count来判断中间相差多少天int weekDay[7] = { 7,1,2,3,4,5,6 };//这个数组的设计一定要在0的位置设置为7map<int,string> WeekDay_to_string={{7,"Sunday"},{1,"Monday"},{2,"Tuesday"},{3,"Wednesday"},{4,"Thursday"},{5,"Friday"},{6,"Saturday"}};int remain = count % 7;//计算一下相差的天数对7求模int today = 4;//当前为星期4if (flag == 0){//说明是未来的日子,today在weekday数组中往后移动while (remain){today++;remain--;if (today > 6)//如果超出数组的范围,置为0{today = 0;}}}else{//说明是之前的日子,today在weekday数组中往前移动while (remain){today--;remain--;if (today < 0)//如果超出数组的范围,置为6{today = 6;}}}cout << WeekDay_to_string[weekDay[today]] << endl;}return 0;
}
3.其他的模拟类型:
其他类型的模拟题通常多变,没有确定的出题方式。然 而,在面对这类题目时,大可不必担心,这类题目是怎么描述的,就按照它说的做,用代码模拟出题面的要求即可。
题目一:
剩下的树_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/f5787c69f5cf41499ba4706bc93700a2?tpId=60&tqId=29497&tPage=2&ru=/kaoyan/retest/1001&qru=/ta/tsing-kaoyan/question-ranking解析:
#include<iostream>
using namespace std;
int main()
{int arr[10001] = { 0 };//利用一共数组存所有的树,多给一个位置//用1表示一棵树,0表示没有,初始化为0int L, M;cin >> L >> M;//输入L和Mfor (int i = 0; i <= L; i++){arr[i] = 1;//将L颗树都置为1}int left, right;while (M){cin >> left >> right;for (int i = left; i <= right; i++){arr[i] = 0;//将移走的树置为0}M--;}int count = 0;//用来统计还剩下的树for (int i = 0; i <= L; i++){if (arr[i] == 1){count++;}}cout << count;return 0;
}
题目二:
手机键盘_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/20082c12f1ec43b29cd27c805cd476cd?tpId=60&tqId=29478&tPage=1&ru=/kaoyan/retest/1001&qru=/ta/tsing-kaoyan/question-ranking思路:
解析:
#include<map>
#include<iostream>
using namespace std;int main()
{//输入某个字母需要花费的时间map<char, int> input_time = {{'a',1},{'b',2},{'c',3},{'d',1},{'e',2},{'f',3},{'g',1},{'h',2},{'i',3},{'j',1},{'k',2},{'l',3},{'m',1},{'n',2},{'o',3},{'p',1},{'q',2},{'r',3},{'s',4},{'t',1},{'u',2},{'v',3},{'w',1},{'x',2},{'y',3},{'z',4}};//某个字母属于哪个按键,用来判断是否与上一次按键冲突需要等待map<char, int> _whichKey = {{'a',2},{'b',2},{'c',2},{'d',3},{'e',3},{'f',3},{'g',4},{'h',4},{'i',4},{'j',5},{'k',5},{'l',5},{'m',6},{'n',6},{'o',6},{'p',7},{'q',7},{'r',7},{'s',7},{'t',8},{'u',8},{'v',8},{'w',9},{'x',9},{'y',9},{'z',9}};char str[100];while (cin >> str){int LastKey = 0;//记录上一次按键为0int sumtime = 0;//用来统计总时间for (int i = 0; str[i] != '\0'; i++){if (LastKey == _whichKey[str[i]]){//如果本次按键与上次按键为同一个按键,需要等待两个时间sumtime += 2;}sumtime += input_time[str[i]];//再累加上每个按键的输入时间//最后记得一定要更新Lastkey值LastKey = _whichKey[str[i]];}cout << sumtime;}return 0;
}