> 文档中心 > 《算法笔记知识点记录》第三章——入门模拟

《算法笔记知识点记录》第三章——入门模拟

在这里插入图片描述

☘前言☘

咕咕咕、鸽子精又回来了。🐒
今天是我开坑的第六次次发文,大家最近应该都在忙期末把?希望看到的你们可以有时间刷刷题。

今天就要开始解决实际问题了,可能是一个简单的问题从简单开始,一步步走到最后,你我皆超神。如果我有哪些没有讲清楚的,欢迎大家联系我,你提出的问题是我修改完善的基础,万分感谢。
欢迎大家加入我的打卡队列,如果你刷完了对你有帮助请你评论一个打卡。

如果觉得这个文章有用还希望大家交出素质三连呀。

🧑🏻作者简介:一个从工业设计改行学嵌入式的年轻人
✨联系方式:2201891280(QQ)
📔源码地址:https://gitee.com/xingleigao/algorithm-notes
全文大约阅读时间: 80min


文章目录

  • ☘前言☘
  • 🍭1.基础知识点
    • 🐶1.1简单模拟
    • 🎧1.2 查找元素
    • 🏑1.3 图形输出
    • 🏏1.4 日期处理
    • 🏂1.5 进制转换
    • 🥍1.6 字符串处理
  • 🐳课后习题

🍭1.基础知识点

学完了所有的C++入门知识,我们就具备了开始解决问题的能力。需要去习惯不同题型的出题习惯,然后才能不断完善直至超神。今天先看两个比较简单的例子。

🐶1.1简单模拟

模拟就是一类题目怎么说你就怎么做的题目,如果不牵扯到算法就是纯粹的模拟,也叫简单模拟,考察的主要是coding能力。 接下来我们看两道题:


【PAT B1001】 害死人不偿命的(3n+1)猜想 (15 分)

题目描述

卡拉兹(Callatz)猜想:
对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。这样一直反复砍下去,最后一定在某一步得到 n=1。卡拉兹在 1950 年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证 (3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……
我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过 1000 的正整数 n,简单地数一下,需要多少步(砍几下)才能得到 n=1?

输入格式:

每个测试输入包含 1 个测试用例,即给出正整数 n 的值。

输出格式:

输出从 n 计算到 1 需要的步数。

样例输入

3

样例输出

5

解题思路

读入题目给出的n后,用while循环语句反复判断n是否为1

  1. 如果n为1,则退出循环。
  2. 否则,如果是偶数就令n为n/2;如果是奇数就令n为``(3 * n + 1)/2。并令计数器 step++。

循环结束时就是所需要的答案。

参考代码

#includeint main(){int n, step = 0;scanf("%d",&n);while(n != 1){if(n %2 == 1)n = (3 * n + 1) / 2;else n = n/2;step++;}printf("%d\n",step);return 0;}

【PAT B1032】 挖掘机技术哪家强

题目描述

为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛。现请你根据比赛结果统计出技术最强的那个学校。

输入格式:

输入在第 1 行给出不超过 10 5 的正整数 N,即参赛人数。随后 N 行,每行给出一位参赛者的信息和成绩,包括其所代表的学校的编号(从 1 开始连续编号)、及其比赛成绩(百分制),中间以空格分隔。

输出格式:

在一行中给出总得分最高的学校的编号、及其总分,中间以空格分隔。题目保证答案唯一,没有并列。

样例输入

6
3 65
2 80
1 100
2 70
3 40
3 0

样例输出

2 150

解题思路

  1. 令数组school[maxn]记录每个学校的总分,初始值为0。对每个读入的学校schID与其对应的分数score,令school[schID]+=score。
  2. 令变量k记录最高总分的学校编号,变量MAX记录最高分,初始值为-1,由于学校的编号是连续的,所以枚举编号1~N-1,不断更新k和MAX就好。

参考代码

#includeconst int maxn = 100010;int school[maxn] = {0};int main(){int n, schID, score;scanf("%d", &n);for(int i = 0;i < n;i++){scanf("%d %d", &schID, &score);school[schID] += score;}int MAX = -1, k = 0;for(int i = 1;i <= n;i++){if(school[i] > MAX){MAX = school[i];k = i;}}printf("%d %d\n", k, MAX);return 0;}

🎧1.2 查找元素

有时会需要这样一种情况:
给定一些元素,然后查找某个满足某条件的元素,这是查找操作需要做的事情。查找是学习写代码的一种基本功,是肯定需要掌握的。
一般来说,如果需要在一个比较小范围数据集里进行查找,那么直接遍历每一个元素就好了。如果需要查找的范围很大,就需要使用二分(4.5节)。看一个简单的例子:

问题 B: 找x

题目描述

输入一个数n(1<=n<=200),然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标(从0开始,若不在数组中则输出-1)。

输入格式:

测试数据有多组,输入n(1<=n<=200),接着输入n个数,然后输入x。

输出格式:

对于每组输入,请输出结果。

样例输入

4
1 2 3 4
3

样例输出

2

解题思路

可以使用一个长度为n的数组保存所有元素,然后从0到n-1寻找元素,如果找到就输出对应的小标,找不到就输出-1

参考代码

#includeconst int maxn = 210;int a[maxn];int main(){int n, x;    while(scanf("%d", &n) != EOF){ for(int i = 0;i < n;i++)     scanf("%d",&a[i]); scanf("%d",&x); int k; for(k = 0;k < n;k++){     if(a[k] == x){  break;     } } if(k != n)printf("%d\n",k); else printf("-1\n");    }return 0;}


🏑1.3 图形输出

有些题目会给出一定的规则,需要我们来根据规则画出对应的图形,其实就是由若干字符按照一定的规则输出。一般分为两种形式

  1. 通过规律直接输出。
  2. 定义一个二维字符数组,按照规律进行填充一次性输出。

看个例子。

【PAT B1036】 跟奥巴马一起编程 (15 分)

题目描述

美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统。2014 年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形。现在你也跟他一起画吧!

输入格式:

输入在一行中给出正方形边长 N(3≤N≤20)和组成正方形边的某种字符 C,间隔一个空格。

输出格式:

输出由给定字符 C 画出的正方形。但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们输出的行数实际上是列数的 50%(四舍五入取整)。

样例输入

10 a

样例输出

aaaaaaaaaa
a      a
a      a
a      a
aaaaaaaaaa

解题思路

由于行数为列数的一半,如果列数是偶数的时候,行数就是n/2;如果列数是奇数的时候,行数就是n/2+1,不如做个统一都是(n+1)/2
通过分析发现,由三部分组成,第1行和第row行都是输出na,对于第2~row-1的每一行,都是先输出一个a最后再输出一个a,然后中间输出col-2个a。
所以我们而已先输出一个a,然后输出row-2个空格,然后输出一个a。

参考代码

#includeint main(){int row, col;char c;scanf("%d %c",&col,&c);row = (col +1)/2;//选取行数for(int i = 0;i < row;i++){if(i == 0 || i == row -1){for(int j = 0;j < col;j++)printf("%c",c);puts("");continue;}printf("%c",c);//输出第一个cfor(int j = 0;j < col -2;j++)printf(" ");if(col > 1)printf("%c",c);puts("");}return 0;}

🏏1.4 日期处理

日期的处理总会让人头疼,因为涉及到处理闰年的问题、大月小月的问题,因此细节比较繁杂,但是只要细心处理细节,这类问题就会很简单。
看个例子:

问题 A: 日期差值

题目描述

有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。

输入格式:

有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD

输出格式:

每组数据输出一行,即日期差值

样例输入

20130101
20130105

样例输出

5

解题思路

不妨设第一个日期早于第二个日期,如果不早交换就可以了。
有一个常用的思路:令日期不断的加1天,直到第一个日期等于第二个日期即可。
具体操作时:
如果加一天之后天数d等于当前月份m所拥有的天数+1,则令月份m+1,同时置天数为1;
如果月份加1后等于13,则年份加1,同时把月份变为1.
为了方便的计算每个月份的天数,不妨设置一个二维数组int month[13][2]来表示闰年和平年的每个月份的天数。
注意:如果想要加快速度,就将第一个日期的年份不断加1到与第二个年份相差1即可,期间根据年份来判断加365还是增加366,最后再不断令天数加1操作。

参考代码

#includeint month[13][2] = {{0,0},{31,31},{28,29},{31,31},{30,30},{31,31},{30,30},{31,31},{31,31},{30,30},{31,31},{30,30},{31,31}};bool isLeap(int year){    //有个口诀,四年一闰。百年不闰,四百年再闰    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;}int main(){    int time1, y1, m1, d1;    int time2, y2, m2, d2;    while(scanf("%d %d", &time1, &time2) != EOF){ if(time1 > time2){     //swap     time1 = time1 ^ time2;     time2 = time1 ^ time2;     time1 = time1 ^ time2; } y1 = time1 / 10000, m1 = time1 % 10000 / 100, d1 = time1 % 100; y2 = time2 / 10000, m2 = time2 % 10000 / 100, d2 = time2 % 100; int ans = 1; //当不相等的时候循环 while(y1 < y2 || m1 < m2 || d1 <d2){     d1++;     if(d1 == month[m1][isLeap(y1)] + 1){  m1++;  d1 = 1;     }     if(m1 == 13){  y1 ++;  m1 = 1;     }     ans++; } printf("%d\n",ans);    }    return 0;}

🏂1.5 进制转换

日常生活使用的进制一般是十进制,而计算机使用的进制是二进制,另外还有八进制,十六进制以及各种数字进制,这就会产生一个问题:对于不同进制如何转换呢?
对于一个P进制转换为Q进制,需要分为两步

  1. 将P进制转换为十进制
    y = a 1∗ P n − 1 + a 2∗ P n − 2 + . . . + a n − 1 ∗ P + a n y = a_1 * P^{n-1}+a_2 * P^{n-2} + ...+ a_{n-1}*P + a_n y=a1Pn1+a2Pn2+...+an1P+an
    这个的相关算法实现也很简单
int y = 0, product = 1;//product 不断乘p得到p的不同次方while(x != 0){y = y + (x % 10) * product;//每次取出最低位 看起来像十进制x = x / 10;product *= p;}
  1. 将十进制转化为Q进制(大名鼎鼎的除留余数法)
    例如要将11转化为2进制
    11 / 2 商5 余1
    5 /2 商2 余1
    2/2 商1 余0
    1/2 商0 余1
    从下往上看 可以得到2进制为(1011)2
int z[40], num = 0;do{z[num++] = y % Q;y /= Q;}while(y != 0);

这里使用do…while的原因是可以规避掉0的特殊处理

【PAT B1022】D进制的A+B (20 分)

题目描述

输入两个非负 10 进制整数 A 和 B (≤230−1),输出 A+B 的 D (1<D≤10)进制数。

输入格式:

输入在一行中依次给出 3 个整数 A、B 和 D。

输出格式:

输出 A+B 的 D 进制数。

样例输入

123 456 8

样例输出

1103

解题思路

先计算A+B的十进制,然后将结果转化为D进制,而十进制转化为D进制的可以使用除留余数法

参考代码

#includeint main(){    int a, b, d;    scanf("%d %d %d", &a, &b, &d);    int sum = a + b;    int ans[31], num = 0;   //ans存放d进制的没一位    do{ ans[num++] = sum % d; sum /= d;    }while(sum != 0);    for(int i = num - 1;i >= 0;i--) printf("%d",ans[i]);    puts("");    return 0;}

🥍1.6 字符串处理

字符串处理是考试中常见的问题,这种题型主要考察的是细心和代码能力一定要注意边界条件的判断。 这种题最好的方法就是多想,多做,积累经验!!

问题 I: 【字符串】回文串

题目描述

读入一串字符,判断是否是回文串。“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。

输入格式:

一行字符串,长度不超过255。

输出格式:

一行字符串,长度不超过255。

样例输入

12321

样例输出

YES

解题思路

假设字符串str的下标从0开始,由于回文串正读和反读都一样所以只要遍历字符串的前一半,不需要读到len/2因为那是正中间的位置,如果全都相等就说明是回文串,否则说明不是。

参考代码

#include#include#includeusing namespace std;const int maxn = 256;bool judge(char str[]){    int len = strlen(str);    for(int i = 0;i < len / 2;i++) if(str[i] != str[len - 1 - i])  return false;    return true;}int main(){    char str[maxn];    while(cin.getline(str,256)){ bool flag = judge(str); if(flag)    printf("YES\n"); else printf("NO\n");    }    return 0;}

【PAT B1009】1009 说反话 (20 分)

题目描述

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

输入格式:

测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用 1 个空格分开,输入保证句子末尾没有多余的空格。

输出格式:

每个测试用例的输出占一行,输出倒序后的句子。

样例输入

Hello World Here I Come

样例输出

Come I Here World Hello

解题思路

使用cin.getline读入一行,用空格对字符串进行分割,并顺序保存到二维数组中。
注意点:

  • 最后如果输出空格会造成错误。
  • 由于PAT是单点测试,所以可以使用以下写法

参考代码

#includeint main(){    int num = 0;    char ans[90][90];    while(scanf("%s",ans[num++]) != EOF)   num++;    for(int i = num - 1;i >= 0;i--){ printf("%s",ans[i]); if(i > 0)   printf(" ");    }    puts("");    return 0;}

解题思路2

有些地方可能是多点测试,那么就得老老实实拆分数组了。

参考代码

#include#include#includeusing namespace std;int main(){    char str[90];    while(cin.getline(str,90)){ int len = strlen(str), row = 0, col = 0; char ans[90][90]; //printf("%s %d",str,len); for(int i = 0;i < len;i++){     if(str[i] != ' ')  ans[row][col++] = str[i];     else{  ans[row][col] = '\0';  row++;  //printf("%d 1",col);  col = 0;     } } ans[row][col] = '\0'; for(int i = row; i >= 0; i--){     printf("%s",ans[i]);     if(i > 0)   printf(" "); } puts("");    }    return 0;}

🐳课后习题

今天的题目难度有点,但是是真滴多(量力而行,太多了,每章不带字母的必做,带字母自己选择),我写完会放题解,大家写完了可以在评论区打卡哟!题解我放评论区吧,这样不用修改文章。

对应章节 题目 相同链接
简单模拟 3.1小节——入门模拟->简单模拟
简单模拟 B1001 害死人不偿命的(3n+1)猜想 (15 分)
简单模拟 B1011 A+B 和 C (15 分)
简单模拟 B1016 部分A+B (15 分)
简单模拟 B1026 程序运行时间 (15 分)
简单模拟 B1046 划拳 (15 分)
简单模拟 B1008 数组元素循环右移问题 (20 分)
简单模拟 B1012 数字分类 (20 分)
简单模拟 B1018 锤子剪刀布 (20 分)
简单模拟 A1042 Shuffling Machine (20 分)
简单模拟 A1046 Shortest Distance (20 分)
简单模拟 A1065 A+B and C (64bit) (20 分)
简单模拟 B1010 一元多项式求导 (25 分)
简单模拟 A1002 A+B for Polynomials (25 分)
简单模拟 A1009 Product of Polynomials (25 分)
查找元素 3.2小节——入门模拟->查找元素
查找元素 B1041 考试座位号 (15 分)
查找元素 B1004 成绩排名 (20 分)
查找元素 B1028 人口普查 (20 分)
查找元素 B1032 挖掘机技术哪家强 (20 分)
查找元素 A1006 Sign In and Sign Out (25 分)
查找元素 A1011 World Cup Betting (20 分)
查找元素 A1036 Boys vs Girls (25 分)
图形输出 3.3小节——入门模拟->图形输出
图形输出 B1036 跟奥巴马一起编程 (15 分)
图形输出 B1027 打印沙漏 (20 分)
图形输出 A1031 Hello World for U (20 分)
日期处理 3.4小节——入门模拟->日期处理
进制转换 3.5小节——入门模拟->进制转换
进制转换 B1022 D进制的A+B (20 分)
进制转换 B1037 在霍格沃茨找零钱 (20 分)
进制转换 A1019 General Palindromic Number (20 分)
进制转换 A1027 Colors in Mars (20 分)
进制转换 A1058 A+B in Hogwarts (20 分)
字符串处理 3.6小节——入门模拟->字符串处理
字符串处理 B1006 换个格式输出整数 (15 分)
字符串处理 B1021 个位数统计 (15 分)
字符串处理 B1031 查验身份证 (15 分)
字符串处理 B1002 写出这个数 (20 分)
字符串处理 B1009 说反话 (20 分)
字符串处理 B1014 福尔摩斯的约会 (20 分) A1061 Dating (20 分)
字符串处理 B1024 科学计数法 (20 分) A1073 Scientific Notation (20 分)
字符串处理 B1048 数字加密 (20 分)
字符串处理 A1001 A+B Format (20 分)
字符串处理 A1005 Spell It Right (20 分)
字符串处理 A1035 Password (20 分)
字符串处理 A1077 Kuchiguse (20 分)
字符串处理 A1082 Read Number in Chinese (25 分)

题解:评论区见,置顶没有就是我没写完0.0,大佬们刷完打个卡
大家加油冲!!!!