模拟问题归纳(包括C++字符串和map的使用

一、图形打印

例题1 输出梯形(清华大学复试上机题)

题目描述:

输入一个高度h,输出一个高度为h、上底边长度为h的梯形。

输入:

一个整数h(1<=h<=1000)。

输出:

h所对应的梯形。

样例输入:

4

样例输出:

****

******

********

**********

代码内容:
#include <cstdio>
char arr[1000][3000];//定义一个全局的数组
int main(){
    int h;
    //char arr[1000][3000];//会报错
    while (scanf("%d", &h) != EOF) {
//        //方法一:先打空格再打*
//        //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");
//        }
        //使用二维数组解决图形打印问题
        //将区域全部填上空格
        for (int i = 0; i < h; ++i) {
            for (int j = 0; j < 3*h-2; ++j) {
                arr[i][j] = ' ';
            }
            arr[i][3*h-2] = '\0';//每一行的边界后一个位置赋值'\0'
        }
        //填充梯形区域
        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");
            //一行行打印
            printf("%s\n", arr[i]);
        }
    }
}
分析:

图形

——>

第i行

空格个数

*的个数

——>

第i行

空格个数

*的个数

****

0

6

4

0

2h-2

h

******

1

4

6

1

2h-4

h+2

********

2

2

8

...

...

...

**********

3

0

10

h-1

0

h+2(h-1)=3h-2

根据分析会发现:

1.每一行*的个数会不断+2;

2.空格个数和*的个数之和为3h-2。

因此我们可以把一个h行3h-3列的二维数组全初始化为空格,最后一列置为'\0'(每遇到一次'\0'是一串字符串,最后打印h行字符串即可)。

3.填充梯形区域时我们从下往上填,最后一行全部填满,然后依次往上每行少填两个*号。

注意

1.while (scanf("%d", &h) != EOF) 是不确定数量的输入处理,EOF全名为end of file,clion中的文件终止符是ctrl+d,VS中的为ctrl+z

2.读取整数和字符串的scanf("%d", &h)和scanf("%s", str),字符数组可以省略&。

3.图案打印问题的一般思路:

  • 申请二维数组(固定大小,放在全局变量的位置)。

  • 根据条件,以任意方开始设置二维数组。

  • 把图案的每一行的边界的后一个位置使用'\0' 赋值(怕忘记可以提前把所有位置设为 '\0' )。

  • 使用printf %s配合循环,打印每一行。

例题2 叠筐

题目描述:

把一个个大小差一園的筐叠上去,使得从上往下看时,边筐花色交错。这个工作现在要让计算机完成,得看你的了。

输入:

输入是一个个三元组。分別是:外筐尺寸n(n为满足0<n <80的奇整数),中心花色字符,外筐花色字符,后二者都为ASCII可见字符。

输出:

输出叠在一起的筐图案,中心花色与外筐花色宇符从内层起交错相叠,多筐相叠时,最外筐的角总是破打磨掉。叠筐与叠筐之间应有一行间隔。

样例输入:

11 B A

5 @ W

样例输出:

AAAAAAAAA

ABBBBBBBBBA

ABAAAAAAABA

ABABBBBBABA

ABABAAABABA

ABABABABABA

ABABAAABABA

ABABBBBBABA

ABAAAAAAABA

ABBBBBBBBBA

AAAAAAAAA

@@@

@WWW@

@W@W@

@WWW@

@@@

代码内容:
#include <cstdio>
int main(){
    int n;//n 外框的长度
    char inner,outter;//内和外的花色
    bool flag = true;//flag用来判断是否是第一个结果,不用打空行
    while (scanf("%d %c %c",&n,&inner,&outter) != EOF){
        //scanf %d %f %o 忽略空白字符
        //scanf %c 可以读取空白字符(空格和换行)
        //scanf %d 如果前面有空格,相当于忽略空白字符
        //处理空行的显示
        if(flag == true){
            flag = false;
        }
        else{
            printf("\n");
        }
        char pattern[80][80] = {0};//二维数组的长度要写固定
        //在定义二维数组时,可以初始化
        //int init = n/2; //第一个点的下标
        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不变,i从x到x+length-1(填充左上到左下)
                pattern[i][j] = curChar;
            }
            for (int i = x, j = y; j < y+length; ++j) {
                // i不变,j从y到y+length-1(填充左上到右上)
                pattern[i][j] = curChar;
            }
            for (int i = x+length-1, j = y; j < y+length; ++j) {
                // (填充左下到右下)
                pattern[i][j] = curChar;
            }
            for (int i = x, j = y+length-1; i < x+length; ++i) {
                // (填充右上到右下)
                pattern[i][j] = curChar;
            }
            // 更换花色
            if(curChar == inner){
                curChar = outter;
            }
            else{
                curChar = inner;
            }
        }
        // 磨掉四个角
        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]);
        }
    }
}
分析:

行/列

0

1

2

3

4

0

@

@

@

1

@

W

W

W

@

2

@

W

@

W

@

3

@

W

W

W

@

4

@

@

@

1.不难发现,外框长5的筐中心坐标为(2,2),外框长11的筐中心坐标为(5,5),即给定的外框长n,中心坐标即为(n/2,n/2)。

2.我们可以发现每个筐的规律即是找到四个顶点然后顺次涂完。每次框框长度会+2,起点行列号都-1 。

所涂个数/各顶点

左上(起点)

右上

左下

右下

1

2,2

2,2

2,2

2,2

3

1,1

1,3

3,1

3,3

5

0,0

0,4

4,0

1.4

3.最后把四个角置为空格。

二、日期问题

例题1 今年的第几天

题目描述:

输入年、月、日,计算该天是本年的第几天。

输入描述:

包括三个整数年(1<=Y<=3000)、月(1<=M<=12)、日(1<=D<=31)。

输出描述:

输入可能有多组测试数据,对于每一组测试数据, 输出一个整数,代表Input中的年、月、日对应本年的第几天。

输入:

1990 9 20

2000 5 1

输出:

263

122

代码示例1:
#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) {
        //到mon月1日的天数 = 到mon-1月1日的天数+第mon-1月的天数
        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;
        if(isLeap == true && mon >= 3){
            printf("%d\n",totalDay[mon] + day + 1);
        }
        else{
            printf("%d\n",totalDay[mon] + day);
        }
    }
}
分析:

1.注意闰年的判断:year%400==0 || year%100!=0 && year%4==0。

2.使用辅助数组记录每月天数:mday[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}

3.到mon月1日的天数 = 到mon-1月1日的天数+第mon-1月的天数,最后加上日数

代码示例2:
#include <cstdio>
//该日期是当年第几天
int main(){
    int year,mon,day;
    int mday[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    while (scanf("%d%d%d",&year,&mon,&day) != EOF){
        int totalDay = 1;
        //nextDay万能方案,一步步走到那一天
        int begMon = 1, begDay = 1;
        while (true){
            if(begMon == mon && begDay == day){
                break;
            }
            ++totalDay;
            bool isLeap = year%400==0 || year%100!=0 && year%4==0;//是否为闰年
            if(isLeap){
                mday[2] = 29;
            }
            else{
                mday[2] = 28;
            }
            ++begDay;
            if(begDay > mday[begMon]){//大于该月天数,进月
                begDay = 1;
                ++begMon;
                // if(begMon > 12){//大于该年月数,进年
                //     begMon = 1;
                //     ++year;
                // }
            }
        }
        printf("%d\n",totalDay);
    }
}
分析:

1.使用nextDay万能方案,一步步走到那一天(要注意循环跳出条件)。

2.大于该月天数,进月;大于该年月数,进年(本题不用进年)。

例题2 Day of Week

描述:

We now use the Gregorian style of dating in Russia. The leap years are years with number divisible by 4 but not divisible by 100, or divisible by 400. For example, years 2004, 2180 and 2400 are leap. Years 2005, 2181 and 2300 are not leap. Your task is to write a program which will compute the day of week corresponding to a given date in the nearest past or in the future using today’s agreement about dating.

输入描述:

There is one single line contains the day number d, month name M and year number y(1000≤y≤3000). The month name is the corresponding English name starting from the capital letter.

输出描述:

Output a single line with the English name of the day of week corresponding to the date, starting from the capital letter. All other letters must be in lower case. Month and Week name in Input/Output: January, February, March, April, May, June, July, August, September, October, November, December Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday

输入:

9 October 2001

14 October 2001

输出:

Tuesday

Sunday

代码示例:
//某日期是星期几
#include <cstdio>
#include <string>
#include <map>
using namespace std;
int main(){
    int mday[13] = {0,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;
    //9 October 2001
    //scanf要使用C风格
    bool isBefore;
    while (scanf("%d%s%d",&day,str,&year) != EOF){
        month = str;//把字符串从C风格转换成C++风格
//        if(month == "January"){
//            mon = 1;
//            //printf也要使用C风格的字符串
//            printf("mon = %d, month = %s\n", mon, month.c_str());
//        }
        mon = monthToint[month];// 使用map从字符串到整数
        if(year < 2023
        || 2023 == year && mon < 1
        || 2023 == year && mon == 1 && day <17){
            isBefore = true;
        }
        else {
            isBefore = false;
        }
        //从begin走到end
        int begYear,begMon,begDay,endYear,endMon,endDay;
        if(isBefore){
            begYear = year;
            begMon = mon;
            begDay = day;
            endYear = 2023;
            endMon = 1;
            endDay = 17;
        }
        else{
            begYear = 2023;
            begMon = 1;
            begDay = 17;
            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%100!=0 && begYear%4==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){
            // (x+totalDay)%7 = 2 --> x = (2+7 - totalDay%7) % 7
            printf("%s\n", intToWeekday[(9 - totalDay%7) % 7].c_str());
        }
        else{
            // 2023.1.17是星期二(2),每隔七天轮一次
            printf("%s\n", intToWeekday[(totalDay+2) % 7].c_str());
        }
    }
}
分析:

1.机试对于字符串的处理:

  • C风格的字符串 字符数组以'\0'结尾

char str[1000];
scanf("%s",str); //输入
printf("%s\n",str) //输出
  • C++风格的字符串 需要加入头文件 #include<string>

string str1 = str; //初始化  "hello"
str1 + "world" //连接  "helloworld"
str1[0] //字符  'h'
str1.length() //长度
str1 == "hello" //判断相等
str1 > "abandon" //判断字典序
  • 比较可使用compare函数 s.compare (pos,n, s2);

若两个串值相同,则返回 0;若S 按字典顺序要先于 S2,则返回负值;反之,则返回正值。

#include <iostream>
#include <string>
using namespace std;
int main ()
{
    string A ("aBcdef");
    string B ("AbcdEf");
    string C ("123456");
    string D ("123dfg");
    //下面是各种比较方法
    int m=A.compare (B); //完整的A和B的比较
    int n=A.compare(1,5,B,0,5); //"Bcdef"和"AbcdEf"比较
    int q=C.compare(0,2,D,0,2); //"123"和"123"比较
    //m = 1, n = -1, q = 0
    return 0;
}
  • 从C++到C风格的转换

str1.c_str();

2.C++风格的map映射 需要加入头文件 #include<map>

//map映射
#include <map>
#include <cstdio>
#include <string>
using namespace std;
int main(){
    // 键 key --> 值 value
    // <键的类型,值的类型>
    map<string,string> myMap = {
            {"宋亚轩","小海螺"},
            {"杨幂","蜜蜂"}
    };
    char str[100];
    scanf("%s", str);
    string name = str;
    //myMap[key] 根据key映射到对应的值(C++风格的字符串)
    printf("%s的粉丝被称为%s\n",name.c_str(),myMap[name].c_str());
}

3.本题需要分类讨论,到今天(2023.1.17星期二)以前和以后的计算方法不一样

  • before:(x+totalDay)%7 = 2 --> x = (2+7 - totalDay%7) % 7

  • future:x = (totalDay+2) % 7

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~許諾~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值