第2章 枚举 & 模拟

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)题目

KY108 Day of Week

(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);
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值