2.1枚举
1.例题2.1 abc
(1)题目
设a、b、c均是0到9之间的数字,abc、bcc是两个三位数,且有:abc+bcc=532。求满足条件的所有a、b、c的值。请输出所有满足题目条件的a、b、c的值。 a、b、c之间用空格隔开。 每个输出占一行。
(2)思路
(3)代码
#include <cstdio>
int main() {
int a, b, c;
for(a = 0; a <= 9; ++a) {
for(b = 0; b <= 9; ++b) {
for(c = 0; c <= 9; ++c) {
// abc + bcc = 532
// 321 + 211 = 532
if(100 * a + 10 * b + c + 100 * b + 10 * c + c == 532) {
printf("%d %d %d\n", a, b, c);
}
}
}
}
}
2.例题2.2 反序数
(1)题目
设N是一个四位数,它的9倍恰好是其反序数(例如:1234的反序数是4321)
求N的值。输出题目要求的四位数,如果结果有多组,则每组结果之间以回车隔开。
(2)思路
反序数:
(3)代码
#include <cstdio>
int Reverse(int n) {
// 名为Reverse的函数,有一个int参数,返回int类型
int remain;
int reverse = 0;
while(true) {
remain = n % 10;
n = n / 10;
reverse = reverse * 10 + remain;
// 当最后一次循环执行时,退出循环
if(n == 0) {
break;
}
}
return reverse;
}
int main() {
int a, b, c, d;
for(a = 1; a <= 9; ++a) {
for(b = 0; b <= 9; ++b) {
for(c = 0; c <= 9; ++c) {
for(d = 0; d <= 9; ++d) {
int n = 1000 * a + 100 * b + 10 * c + d;
if(n * 9 == Reverse(n)) {
printf("%d\n", n);
}
}
}
}
}
}
3.例题2.3 对称平方数
(1)题目
打印所有不超过256,其平方具有对称性质的数。如2,11就是这样的数,因为2*2=4,11*11=121。
(2)代码
#include <cstdio>
//求逆序数
int Reverse(int n) {
// 名为Reverse的函数,有一个int参数,返回int类型
int remain;
int reverse = 0;
while(true) {
remain = n % 10;
n = n / 10;
reverse = reverse * 10 + remain;
// 当最后一次循环执行时,退出循环
if(n == 0) {
break;
}
}
return reverse;
}
int main() {
int i = 0;
for(i = 1; i <= 256; ++i) {
if(i * i == Reverse(i * i)) {
printf("%d\n", i);
}
}
}
4.习题2.1 与7无关的数
(1)题目
一个正整数,如果它能被7整除,或者它的十进制表示法中某个位数上的数字为7, 则称其为与7相关的数.现求所有小于等于n(n<100)的与7无关的正整数的平方和。
(2)思路
先用aboutSeven()函数判断是否是与7有关的数字
再用sumSeven()函数计算非7相关的数字平方和
(3)代码
#include <cstdio>
bool aboutSeven(int n) {
if(n % 7 == 0 || n % 10 == 7) {
return false;
}
return true;
}
int sumSeven(int n) {
int sum = 0;
for(int i = 0; i <= n; ++i) {
if(aboutSeven(i)) {
// printf("i = %d\n", i);
sum += i * i;
}
}
return sum;
}
int main() {
int n, sum;
while(scanf("%d", &n) != EOF) {
sum = sumSeven(n);
printf("%d\n", sum);
}
return 0;
}
5.习题2.2 百鸡问题
(1)题目
用小于等于n元去买100只鸡,大鸡5元/只,小鸡3元/只,还有1/3元每只的一种小鸡,分别记为x只,y只,z只。编程求解x,y,z所有可能解。
(2)思路
主要套路是将所有的数字都放大3倍,不然运用float类型的数字非常难计算且编写代码
(3)代码
#include <cstdio>
void chicken(int money){
for(int i = 0; i<=100; i++){
for(int j = 0 ; j <= 100 ; j++ ){
for(int k = 0 ; k <= 100 ;k++){
if((15*i+9*j+k)<=3*money && ((i+j+k) == 100))
printf("x=%d,y=%d,z=%d\n",i,j,k);
}
}
}
}
int main(){
int money = 0;
while(scanf("%d", &money) != EOF) {
chicken(money);
}
return 0;
}
6.习题2.3 Old Bill
(1)题目
N只火鸡的价格是¥_XYZ_,火鸡的总数N在1到99之间。价格由五位数组成,两边的数字由于褪色而看不清,所以只能看到中间的三位数。假设第一个数字非零,每只火鸡的价格是整数,并且所有火鸡的价格相同。给定N,X,Y和Z,编写一个程序来猜测两边褪色的数字和火鸡的原始价格。如果有很多个价格符合题意,那么输出最昂贵的那个
(2)思路
把a和从9到1、0遍历,可以输出最大值而结束程序
break语句可以直接跳出循环
若是有结果,那么标记f直接设为1,在跳出循环后不会打印0
若没有结果,那么标记f为0,!0为true,进入循环直接打印0
(3)代码
#include <cstdio>
int main() {
int n, x, y, z;//n火鸡数、xyz原价格中间三位
while (scanf("%d", &n) != EOF) {
scanf("%d %d %d", &x, &y, &z);
//tot原价格、f标记是否存在能够整除火鸡数n的价格
//这里选择从9枚举到1是为了第一次输出就是最高价格
int tot, f = 0;
for(int a = 9; a >= 1; a--){//a控制原价格的万位[1,9]
for(int b = 9; b >= 0; b--){//b控制原价格的个位[0,9]
tot = a * 10000 + x * 1000 + y * 100 + z * 10 + b;
if(tot % n == 0){//如果原价格tot能够整除火鸡数n
f = 1;//则将整除标记置1
printf("%d %d %d\n", a, b, tot / n);
break;
}
}
if(f) break;//如果已经整除,则跳出枚举
}
if(!f) printf("0\n");//如果没有可以整除的价格,则打印0
}
return 0;
}
2.2模拟
1.模拟定义及性质
(1)阅读题目:场景——>代码
(2)东西——>数据结构、数组、二维数组
(3)交互
(4)题型:图形打印、日期问题、其他模拟
2.图案打印问题的一般思路(二维数组 + 数字规律)
1.申请二维数组(固定大小,放在全局变量的位置)
(提前将所有位置设为'\0')
2.根据条件,从任意方向开始,设置二维数组
3.把图案的每一行的边界的后一个位置使用'\0'赋值
4.使用printf %s配合循环,打印每一行
3.图形排版-例题2.4 输出梯形(直接打印)
(1)题目
(2)思路
(3)代码
for循环
#include <cstdio>
int main() {
int h;
scanf("%d", &h);
for(int i = 0; i < h; ++i) {
for(int j = 0; j < 2 * h - 2 - 2 * i; ++j) {
printf(" ");
}
for(int j = 0; j < h + 2 * i; ++j) {
printf("*");
}
printf("\n");
}
}
不确定数量的输入
#include <cstdio>
int main() {
int h;
while(scanf("%d", &h) != EOF) {
// EOF实在stdio.h中声明的,其实就是-1
for(int i = 0; i < h; ++i) {
for(int j = 0; j < 2 * h - 2 - 2 * i; ++j) {
printf(" ");
}
for(int j = 0; j < h + 2 * i; ++j) {
printf("*");
}
printf("\n");
}
}
}
EOF实在stdio.h中声明的,其实就是-1
Clion:ctrl + d:文件终止符 End of file
VSCode:ctrl + z
4.图形排版-例题2.4 输出梯形(二维数组)
(1)思路
①h的范围,下底边是 h+2*(h-2)=3h-2
高是h
arr[0][0] ===> a[n-1][3n-3]
②全天上空格
③从下往上填*
(2)代码
#include <cstdio>
//定义一个全局的数组
char arr[1000][3000];
int main() {
int h;
while(scanf("%d", &h) != EOF) {
// 将区域全部填上空格
for(int i = 0; i < h; ++i) {
for(int j = 0; j < 3 * h - 3; ++j) {
arr[i][j] = ' ';
}
}
// 填充梯形区域
int beg = 0;
for(int i = h - 1; i >= 0; --i) {
// 从下往上填充
for(int j = beg; j < 3 * h - 2; ++j) {
arr[i][j] = '*';
}
beg = beg + 2;
}
for (int i = 0; i < h; ++i) {
for(int j = 0; j < 3 * h - 2; ++j) {
printf("%c", arr[i][j]);
}
printf("\n");
}
}
}
关于字符串数组的输出,以下两种代码是一个效果的
for (int i = 0; i < h; ++i) {
for(int j = 0; j < 3 * h - 2; ++j) {
printf("%c", arr[i][j]);
}
printf("\n");
}
for (int i = 0; i < h; ++i) {
printf("%s\n", arr[i]);
}
5.图像排版-例题2.5 叠框
(1)题目
(2)思路
以下是11行的数组的表达式,起点是【5,5】 ,然后以此找规律
(3)代码
#include<cstdio>
int main() {
// 外框的长度
int n;
// 内和外的花色
char inner, outter;
// flag用来判断是否是第一个结果
bool flag = true;
while(scanf("%d %c %c", &n, &inner, &outter) != EOF) {
// 处理空行的显示
if(flag == true) {
flag = false;
} else {
printf("\n");
}
// 在定义二维数组时,可以初始化
// 二维数组的长度要写固定的
char pattern[80][80] = {0};
// 外框的长为length
int length = 1;
int x, y;
// 用来填充的花色
char curChar = inner;
for(length = 1, x = n / 2, y = n / 2; length <= n; length = length + 2, --x, --y) {
// x 和 y是起点的下标
// 填满一个长度为length的正方形
// 左边
for(int i = x, j = y; i < x + length; ++i) {
// j=y不变的,i从x到x+length-1
pattern[i][j] = curChar;
}
// 上边
for(int i = x, j = y; j < y + length; ++j) {
// i=x不变的,j从y到y+length-1
pattern[i][j] = curChar;
}
// 下边
for(int i = x + length - 1, j = y; j < y + length; ++j) {
// i=x+length-1不变的,j从y到y+length-1
pattern[i][j] = curChar;
}
// 右边
for(int i = x, j = y + length - 1; i < x + length; ++i) {
// j=y不变的,i从x到x+length-1
pattern[i][j] = curChar;
}
// 更换花色
if(curChar == inner) {
curChar = outter;
} else {
curChar = inner;
}
}
// 磨掉4个角
if(n != 1) {
pattern[0][0] = ' ';
pattern[0][n - 1] = ' ';
pattern[n - 1][0] = ' ';
pattern[n - 1][n - 1] = ' ';
}
for (int i = 0; i < n; ++i) {
printf("%s\n", pattern[i]);
}
}
}
6.日期问题
思考难度不大:都是套路题目
代码的编写量打:考察熟练度
数组 + 循环 ——> 调试代码
(1)给出年份,问是否是闰年?
year % 400 == 0 || year % 100 != 0 && year % 4 == 0
&&优先于||
(2)问一个月中有多少天
if(mon == 1)
else if(mon == 2)
辅助数组mday[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
用空间换时间
7.日期问题-例题2.6 今年的第几天?
(1)题目
输入年、月、日,计算该天是本年的第几天。
包括三个整数年(1<=Y<=3000)、月(1<=M<=12)、日(1<=D<=31)。
输入可能有多组测试数据,对于每一组测试数据, 输出一个整数,代表Input中的年、月、日对应本年的第几天。
(2)思路
求1990.9.20是1990年的第几天?
方案一:先算从1.1到9.1,再算9.1到9.20
方案二:(万能方案)
1990.1.1—>1990.1.2—>1990.1.3—>……1990.9.20
(3)代码
方案一
#include <cstdio>
int main() {
int year, mon, day;
int mday[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int totalDay[13] = {0};
// 计算整月的天数
for(int mon = 2; mon <= 12; ++mon) {
totalDay[mon] = totalDay[mon - 1] + mday[mon - 1];
}
while(scanf("%d%d%d", &year, &mon, &day) != EOF) {
// 如果是闰年
bool isLeap = year % 400 == 0 || year % 100 != 0 && year % 4 == 0;
// 是闰年,且月份大于3月,那么最后的结果需要加上1
if(isLeap == true && mon >= 3) {
printf("%d\n", totalDay[mon] + day + 1);
} else {
printf("%d\n", totalDay[mon] + day);
}
}
}
1990 9 20
2000 5 1
^D
263
122
方案二:一天天算(掰手指)
#include <cstdio>
int daytab[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool IsLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
}
int main() {
int year, month, day;
while(scanf("%d%d%d", &year, &month, &day) != EOF) {
int number = 0;
int row = IsLeapYear(year);
for(int j = 0; j < month; ++j) {
number += daytab[row][j];
}
number += day;
printf("%d\n", number);
}
return 0;
}
8.日期问题-例题2.7 打印日期
(1)题目
描述
给出年分m和一年中的第n天,算出第n天是几月几号。
输入描述:
输入包括两个整数y(1<=y<=3000),n(1<=n<=366)。
输出描述:
可能有多组测试数据,对于每组数据, 按 yyyy-mm-dd的格式将输入中对应的日期打印出来。
(2)思路
(3)代码
#include <cstdio>
int daytab[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool IsLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
}
int main() {
int year, month, day;
int number;
while(scanf("%d%d", &year, &number) != EOF) {
month = 0;
int row = IsLeapYear(year);
// 把天数从1月的31填开始减,一直减到它小于一个月的天数
while(number > daytab[row][month]) {
number -= daytab[row][month];
month++;
}
day = number;
printf("%04d-%02d-%02d\n", year, month, day);
}
return 0;
}
9.日期问题-例题2.8 日期累加
(1)题目
描述:
设计一个程序能计算一个日期加上若干天后是什么日期。
输入描述:
输入第一行表示样例个数m,接下来m行每行四个整数分别表示年月日和累加的天数。
输出描述:
输出m行,每行按yyyy-mm-dd的个数输出。
(2)代码
#include <cstdio>
int daytab[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool IsLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
}
// 如果是闰年的话就返回366,如果不是闰年就返回365
int NumberOfYear(int year) {
if(IsLeapYear(year)) {
return 366;
} else {
return 365;
}
}
int main() {
int year, month, day;
int number;
int caseNumber;
scanf("%d", &caseNumber);
while(caseNumber--) {
scanf("%d%d%d%d", &year, &month, &day, &number);
int row = IsLeapYear(year);
// 计算机已经输入的这个日期在这一年中是第几天
for(int j = 0; j < month; ++j) {
number += daytab[row][j];
}
number += day;
// 如果天数大于这一年的天数,那么需要把这一的天数减去(判断是否是闰年),如此减到number小于365
while(number > NumberOfYear(year)) {
number -= NumberOfYear(year);
year++;
}
month = 0;
row = IsLeapYear(year);
while(number > daytab[row][month]) {
number -= daytab[row][month];
month++;
}
day = number;
printf("%04d-%02d-%02d\n", year, month, day);
}
return 0;
}
10.日期问题-今天是星期几
(1)题目
(2)代码
#include <cstdio>
#include <string>
#include <map>
using namespace std;
int main() {
int mday[31] = {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
string intToWeekday[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
map<string, int> monthToint = {
{"January", 1},
{"February", 2},
{"March", 3},
{"April", 4},
{"May", 5},
{"June", 6},
{"July", 7},
{"August", 8},
{"September", 9},
{"October", 10},
{"November", 11},
{"December", 12}
};
int year, mon, day;
char str[100];
string month;
bool isBefore;
while(scanf("%d%s%d", &day, str, &year) != EOF) {
month = str;
mon = monthToint[month]; // 从字符串到整数
if(year < 2022
|| year == 2022 && mon < 11
|| year == 2022 && mon == 11 && day < 3) {
isBefore = true;
}
else {
isBefore = false;
}
// 从Begin走到End
int begYear, begMon, begDay, endYear, endMon, endDay;
if(isBefore) {
begYear = year;
begMon = mon;
begDay = day;
endYear = 2022;
endMon = 11;
endDay = 3;
}
else {
begYear = 2022;
begMon = 11;
begDay = 3;
endYear = year;
endMon = mon;
endDay = day;
}
int totalDay = 0;
while(true) {
if(begYear == endYear && begMon == endMon && begDay == endDay) {
break;
}
++totalDay;
// nextDay
bool isLeap = begYear % 400 == 0 || begYear % 4 == 0 && begYear % 100 != 0;
if(isLeap) {
mday[2] = 29;
} else {
mday[2] = 28;
}
++begDay;
if(begDay > mday[begMon]) {
begDay = 1;
++begMon;
if(begMon > 12) {
begMon = 1;
++begYear;
}
}
}
if(isBefore) {
printf("%s\n", intToWeekday[(11 - totalDay % 7) % 7].c_str());
} else {
printf("%s\n", intToWeekday[(totalDay + 4) % 7].c_str());
}
}
}
11.日期问题-例题2.9剩下的树
(1)题目
(2)代码
#include <cstdio>
int main() {
int tree[10001];
int L, M;
scanf("%d%d", &L, &M);
for(int i = 0; i <= L; ++i) {
tree[i] = 1;
}
for(int idx = 0; idx < M; ++idx) {
int left, right;
scanf("%d%d", &left, &right);
for(int i = left; i <= right; ++i) {
tree[i] = 0;
}
}
int totalNumber = 0;
for(int i = 0; i <= L; ++i) {
if(tree[i] == 1) {
++totalNumber;
}
}
printf("%d\n", totalNumber);
return 0;
}
12.日期问题-例题2.10九宫格
(1)题目
(2)思想
例如www:首先一个w要按几下 map<char, int>
w属于哪个案件,是否需要等待map<char, int>
(3)代码
#include <map>
#include <cstdio>
using namespace std;
int main() {
// 某个字母需要输出多长时间
map<char, int> inputTime = {
{'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> keyMap = {
{'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[101];
while(scanf("%s", str) != EOF) {
// 初始的时候,lastInput置为和其他所有按键都不同的键
int lastInput = 1;
int totalTime = 0;
for(int i = 0; str[i] != '\0'; ++i) {
// 遍历C风格的字符串 str[i]本次将要按下的字母
// 判断一下是否需要等待
if(lastInput == keyMap[str[i]]) {
totalTime = totalTime + 2; // 等待
}
totalTime = totalTime + inputTime[str[i]]; // 输入本字母所需要的时间
lastInput = keyMap[str[i]];// 记录本次按下的数字
}
printf("%d\n", totalTime);
}
}