分数四则运算(结构)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

分数的分子和分母可用一个结构类型来表示。
编写实现两个分数加(addFS),减(subFS),乘(mulFS),除(divFS)的函数(要求计算结果分数是简化的),以及打印一个分数(printFS),计算两个整数最大公约数的函数(getGCD)。
注意:不能定义全局变量

输入

测试数据的组数 t
第一组第一个分数
第一组第二个分数
第二组第一个分数
第二组第二个分数
……

输出

第一组两个分数的和
第一组两个分数的差
第一组两个分数的积
第一组两个分数的商
第二组两个分数的和
第二组两个分数的差
第二组两个分数的积
第二组两个分数的商
……

样例输入

3
1/2
2/3
3/4
5/8
21/23
8/13

样例输出

7/6
-1/6
1/3
3/4

11/8
1/8
15/32
6/5

457/299
89/299
168/299
273/184

提示

求两数a、b的最大公约数可采用辗转相除法,又称欧几里得算法,其步骤为:

  1. 交换a, b使a > b;
  2. 用a除b得到余数r,若r=0,则b为最大公约数,退出;
  3. 若r不为0,则用b代替a, r代替b,此时a,b都比上一次的小,问题规模缩小了;
  4. 继续第2步。

解决方案

想想化简部分还是可以抽成一个inline函数的,但是懒得改了。

#include <iostream>

class Fraction {
public:
    Fraction() = default;

    Fraction(int numerator, int denominator) : numerator(numerator), denominator(denominator) {}

    Fraction operator+(const Fraction &rhs) {
        int numerator_tmp = this->numerator * rhs.denominator + rhs.numerator * this->denominator;
        int denominator_tmp = this->denominator * rhs.denominator;
        int gcd_tmp = gcd(numerator_tmp, denominator_tmp);
        return {numerator_tmp / gcd_tmp, denominator_tmp / gcd_tmp};
    }

    Fraction operator-(const Fraction &rhs) {
        return (*this + Fraction(-rhs.numerator, rhs.denominator));
    }

    Fraction operator*(const Fraction &rhs) {
        int numerator_tmp = this->numerator * rhs.numerator;
        int denominator_tmp = this->denominator * rhs.denominator;
        int gcd_tmp = gcd(numerator_tmp, denominator_tmp);
        return {numerator_tmp / gcd_tmp, denominator_tmp / gcd_tmp};
    }

    Fraction operator/(const Fraction &rhs) {
        int numerator_tmp = rhs.denominator, denominator_tmp = rhs.numerator;
        return (*this * Fraction(numerator_tmp, denominator_tmp));
    }

    friend std::istream &operator>>(std::istream &is, Fraction &rhs) {
        is >> rhs.numerator;
        is.get();
        is >> rhs.denominator;
        return is;
    }

    friend std::ostream &operator<<(std::ostream &os, const Fraction &rhs) {
        if (rhs.denominator < 0) {
            return os << -rhs.numerator << '/' << -rhs.denominator;
        } else {
            return os << rhs.numerator << '/' << rhs.denominator;
        }
    }

private:
    int numerator, denominator;

    static int gcd(int lhs, int rhs) {
        int tmp;
        while (rhs != 0) {
            tmp = rhs;
            rhs = lhs % rhs;
            lhs = tmp;
        }
        return lhs;
    }
};

int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        Fraction a{}, b{};
        std::cin >> a >> b;
        std::cout << a + b << std::endl
                  << a - b << std::endl
                  << a * b << std::endl
                  << a / b << std::endl
                  << std::endl;
    }
    return 0;
}

扑克牌排序(结构体)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

自定义结构体表示一张扑克牌,包含类型——黑桃、红桃、梅花、方块、王;大小——2,3,4,5,6,7,8,9,10,J,Q,K,A,小王(用0表示)、大王(用1表示)。输入n,输入n张扑克牌信息,从大到小输出它们的排序结果。
假设扑克牌的排序规则是大王、小王为第一大、第二大,剩余52张扑克牌按照先花色后大小排序。
花色:黑桃>红桃>梅花>方块。
大小: A>K>Q>J>>10>9>…>2。
提示:百度sort函数、strstr函数使用。

输入

测试次数t
每组测试数据两行:
第一行:n,表示输入n张扑克牌
第二行:n张扑克牌信息,格式见样例

输出

对每组测试数据,输出从大到小的排序结果

样例输入

3
5
黑桃4 红桃10 梅花Q 方块K 黑桃A
10
大王 梅花10 红桃K 方块9 黑桃2 梅花A 方块Q 小王 黑桃8 黑桃J
5
红桃K 梅花K 黑桃K 方块K 小王

样例输出

黑桃A 黑桃4 红桃10 梅花Q 方块K
大王 小王 黑桃J 黑桃8 黑桃2 红桃K 梅花A 梅花10 方块Q 方块9
小王 黑桃K 红桃K 梅花K 方块K

提示

解决方案

突然发现我之前发过这题的题解…是我很久以前写的了好像,有兴趣看的话可以直接站内搜索。

如果你试图初始化一个静态的例如某些全局变量,那么可能会得到Clang-Tidy的警告,像这样:Initialization of 'variable_name' with static storage duration may throw an exception that cannot be caught。我不建议无视这个警告。解决方法可以是用一个静态的getter函数来包围这个变量,使得该变量的初始化时机从以前的main()函数执行前延迟到首次调用这个getter函数。下面的get_num_size_map()算是一个小例子,更多信息请访问引用链接。

#include <iostream>
#include <algorithm>
#include <iterator>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <cassert>

struct Poker {
    explicit Poker(const std::string &raw) {
        if (raw.find("黑桃") != std::string::npos) {
            this->suit = "黑桃";
        } else if (raw.find("红桃") != std::string::npos) {
            this->suit = "红桃";
        } else if (raw.find("梅花") != std::string::npos) {
            this->suit = "梅花";
        } else if (raw.find("方块") != std::string::npos) {
            this->suit = "方块";
        } else if (raw.find("小王") != std::string::npos) {
            this->suit = "小王";
            this->num = "0";
            return;
        } else {
            this->suit = "大王";
            this->num = "1";
            return;
        }
        if (raw.find("10") == std::string::npos) {
            this->num = raw.back();
        } else {
            this->num = "10";
        }
    }

    size_t size() const {
        size_t size = 0;
        size += get_suit_size_map()[this->suit];
        size += get_num_size_map()[this->num];
        return size;
    }

    bool operator<(const Poker &rhs) {
        return this->size() < rhs.size();
    }

    friend std::ostream &operator<<(std::ostream &os, const Poker &rhs) {
        os << rhs.suit;
        if (!(rhs.num == "0" || rhs.num == "1")) {
            os << rhs.num;
        }
        return os;
    }

    std::string suit, num;
private:
    static std::map<std::string, int> get_suit_size_map() {
        static const std::map<std::string, int> suit_size = {
                {"大王", 5 * 13}, {"小王", 4 * 13},
                {"黑桃", 3 * 13}, {"红桃", 2 * 13},
                {"梅花", 1 * 13}, {"方块", 0 * 13},
        };
        return suit_size;
    }

    static std::map<std::string, int> get_num_size_map() {
        static const std::map<std::string, int> num_size = {
                {"2",  0}, {"3",  1}, {"4",  2}, {"5",  3},
                {"6",  4}, {"7",  5}, {"8",  6}, {"9",  7},
                {"10", 8}, {"J",  9}, {"Q",  10}, {"K",  11},
                {"A",  12}, {"0",  0}, {"1",  0},
        };
        return num_size;
    }
};

int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        size_t size;
        std::cin >> size;
        if (std::cin.get() == '\r') { std::cin.get(); }
        std::string line;
        std::getline(std::cin, line);
        std::istringstream iss(line);
        std::vector<Poker> pokers{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
        assert(!pokers.empty());
        std::sort(pokers.begin(), pokers.end(), [](const Poker &lhs, const Poker &rhs) { return lhs.size() > rhs.size(); });
        std::cout << pokers.front();
        for (size_t i = 1; i < pokers.size(); ++i) {
            std::cout << ' ' << pokers[i];
        }
        std::cout << std::endl;
    }
    return 0;
}

引用:
c++ – How do I iterate over the words of a string? – Stack Overflow
Initialization – cppreference.com
What is this warning in C++: initialization of ‘-‘ with static storage duration may throw an exception that cannot be caught? – Quora
c++ – How to catch exception thrown while initializing a static member – Stack Overflow
c++ – How to deal with static storage duration warnings? – Stack Overflow

访问数组元素(引用)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

输入n,输入n个数,计算n个数的和并输出。
假设主函数定义如下,不可修改。请补齐put函数。

输入

测试次数
每组测试数据一行,正整数n(1~1000),后跟n个整数。

输出

每组测试数据输出一行,即n个整数的和。

样例输入

3
4 10 20 30 40
10 1 2 3 -1 -2 -3 1 2 3 4
5 0 0 0 0 10

样例输出

sum=100
sum=10
sum=10

提示

解决方案

不明白这种混杂着C89和C99还有C++风格的代码有什么理由不让人改

#include <iostream>

const size_t N = 1000;

int &put(int *array, size_t size) {
    return *(array + size);
}

int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        int array[N]{};
        size_t size;
        std::cin >> size;
        for (size_t i = 0; i < size; ++i) {
            std::cin >> put(array, i);
        }
        int sum = 0;
        for (size_t i = 0; i < size; ++i) {
            sum += array[i];
        }
        std::cout << "sum=" << sum << std::endl;
    }
    return 0;
}

求最大值最小值(引用)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

编写函数void find(int *num,int n,int &minIndex,int &maxIndex),求数组num(元素为num[0],num[1],…,num[n-1])中取最小值、最大值的元素下标minIndex,maxIndex(若有相同最值,取第一个出现的下标。)
输入n,动态分配n个整数空间,输入n个整数,调用该函数求数组的最小值、最大值下标。最后按样例格式输出结果。
改变函数find功能不计分。

输入

测试次数
每组测试数据一行:数据个数n,后跟n个整数

输出

每组测试数据输出两行,分别是最小值、最大值及其下标。具体格式见样例。多组测试数据之间以空行分隔。

样例输入

2
5 10 20 40 -100 0
10 23 12 -32 4 6 230 100 90 -120 15

样例输出

min=-100 minindex=3
max=40 maxindex=2

min=-120 minindex=8
max=230 maxindex=5

提示

解决方案

#include <iostream>

void find(const int *array, size_t size, size_t &min_index, size_t &max_index) {
    for (size_t i = 0; i < size; ++i) {
        if (array[min_index] > array[i]) {
            min_index = i;
        }
        if (array[max_index] < array[i]) {
            max_index = i;
        }
    }
}

int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        size_t size;
        std::cin >> size;
        int *array = new int[size];
        for (size_t i = 0; i < size; ++i) {
            std::cin >> array[i];
        }
        size_t min_index = 0, max_index = 0;
        find(array, size, min_index, max_index);
        std::cout << "min=" << array[min_index] << " minindex=" << min_index << std::endl
                  << "max=" << array[max_index] << " maxindex=" << max_index << std::endl
                  << std::endl;
    }
    return 0;
}

三数论大小(引用)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

输入三个整数,然后按照从大到小的顺序输出数值。
要求:定义一个函数,无返回值,函数参数是三个整数参数的引用,例如int &a, int &b, int &c。在函数内通过引用方法来对三个参数进行排序。主函数调用这个函数进行排序。
要求:不能直接对三个整数进行排序,必须通过函数而且是引用的方法。

输入

第一行输入t表示有t个测试实例
第二行起,每行输入三个整数
输入t行

输出

每行按照从大到小的顺序输出每个实例,三个整数之间用单个空格隔开

样例输入

3
2 4 6
88 99 77
111 333 222

样例输出

6 4 2
99 88 77
333 222 111

提示

解决方案

#include <iostream>
 
void swap(int &lhs, int &rhs) {
    int tmp = lhs;
    lhs = rhs;
    rhs = tmp;
}
 
void sort(int &a, int &b, int &c) {
    if (c > b) {
        swap(c, b);
    }
    if (c > a) {
        swap(c, a);
    }
    if (b > a) {
        swap(b, a);
    }
}
 
int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        int a, b, c;
        std::cin >> a >> b >> c;
        sort(a, b, c);
        std::cout << a << ' ' << b << ' ' << c << std::endl;
    }
    return 0;
}

字符串合并(指针与函数)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

定义一个函数char *strAdd(char *s1, char *s2),其返回的是s1和s2两个字符串合并后的值。(要求不能改变s1和s2)

输入

测试数据的组数 t
第一组字符串1
第一组字符串2
第二组字符串1
第二组字符串2
…….

输出

第一组字符串1 第一组字符串2 第一组字符串1和字符串2的合并
第二组字符串1 第二组字符串2 第二组字符串1和字符串2的合并
………

样例输入

2
hello
world
string
concatation

样例输出

hello world helloworld
string concatation stringconcatation

提示

解决方案

#include <iostream>
#include <cstring>

char *strcat(char *str1, char *str2) {
    size_t str1_length = strlen(str1), str2_length = strlen(str2);
    auto buffer = new char[str1_length + str2_length + 1];
    auto buffer_ptr = buffer, str1_ptr = str1, str2_ptr = str2;
    while (*str1_ptr) {
        *(buffer_ptr++) = *(str1_ptr++);
    }
    while (*str2_ptr) {
        *(buffer_ptr++) = *(str2_ptr++);
    }
    *buffer_ptr = '\0';
    return buffer;
}

int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        char str1[1024], str2[1024];
        std::cin >> str1 >> str2;
        std::cout << str1 << ' ' << str2 << ' ' << strcat(str1, str2) << std::endl;
    }
    return 0;
}

函数调用(函数指针)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

定义并实现三个函数:
第一个函数是整数函数,返回类型为整数,参数是一个整数变量,操作是求该变量的平方值
第二个函数是浮点数函数,返回类型为浮点数,参数是一个浮点数变量,操作是求该变量的平方根值。求平方根可以使用函数sqrt(浮点参数),将返回该参数的平方根,在VC中需要头文件cmath。
第三个函数是字符串函数,无返回值,参数是一个字符串指针,操作是把这个字符串内所有小写字母变成大写。
要求:定义三个函数指针分别指向这三个函数,然后根据调用类型使用函数指针来调用这三个函数。不能直接调用这三个函数。
如果类型为I,则通过指针调用整数函数;如果类型为F,则通过指针调用浮点数函数;如果类型为S,则通过指针调用字符串函数

输入

第一行输入一个t表示有t个测试实例
每行先输入一个大写字母,表示调用类型,然后再输入相应的参数
依次输入t行

输出

每行输出调用函数后的结果

样例输入

5
S shenzhen
I 25
F 6.25
I 31
S China

样例输出

SHENZHEN
625
2.5
961
CHINA

提示

解决方案

#include <iostream>
#include <cmath>

int square(int number) {
    return number * number;
}

double square_root(double number) {
    return sqrt(number);
}

void to_upper_case(char *string) {
    while (char ch = *string) {
        if ('a' <= ch && ch <= 'z') {
            *string -= ('a' - 'A');
        }
        string += 1;
    }
}

int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        char type;
        std::cin >> type;
        switch (type) {
            case 'I': {
                int number;
                std::cin >> number;
                int (*function_ptr)(int) = square;
                std::cout << function_ptr(number) << std::endl;
                break;
            }
            case 'F': {
                double number;
                std::cin >> number;
                double (*function_ptr)(double) = square_root;
                std::cout << function_ptr(number) << std::endl;
                break;
            }
            case 'S': {
                char string[1024];
                std::cin >> string;
                void (*function_ptr)(char *) = to_upper_case;
                function_ptr(string);
                std::cout << string << std::endl;
                break;
            }
            default:
                exit(-1);
        }
    }
    return 0;
}

字符串比较(指针与字符)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

编写一个函数比较两个字符串,参数是两个字符指针(要求显式定义,例如char *S, char *T),比较字符串S和T的大小。如果S大于T,则返回1,如果S小于T则返回-1,如果S与T相等则返回0。
比较规则:
1.把两个字符串的相同位置上的字符进行比较,字符的大小比较以ASCII值为准
2.在比较中,如果字符串S的字符大于字符串T的字符的数量超过小于的数量,则认为S大于T,如果等于则S等于T,如果小于则S小于T
例如S为aaccdd,T为eebbbb,每个位置比较得到S前两个字母都小于T,但后4个字母都大于T,最终认为S大于T
3.如果两个字符串长度不同,则更长的字符串为大
在主函数中输入两个字符串,并调用该函数进行判断,在判断函数中必须使用函数参数的指针进行字符比较

输入

输入t表示有t个测试实例
接着每两行输入两个字符串
依次输入t个实例

输出

每行输出一个实例的比较结果

样例输入

3
aaccdd
eebbbb
AAbb++
aaEE*-
zznnkk
aaaaaaa

样例输出

1
0
-1

提示

解决方案

#include <iostream>
#include <cstring>

int strcmp(char *str1, char *str2) {
    size_t str1_length = strlen(str1), str2_length = strlen(str2);
    if (str1_length > str2_length) {
        return 1;
    } else if (str1_length < str2_length) {
        return -1;
    }
    unsigned int value1 = 0, value2 = 0;
    while (*str1 != '\0') {
        if (*str1 == *str2) {
            continue;
        }
        if (*(str1++) > *(str2++)) {
            value1 += 1;
        } else {
            value2 += 1;
        }
    }
    if (value1 > value2) {
        return 1;
    } else if (value1 < value2) {
        return -1;
    } else {
        return 0;
    }
}

int main() {
    size_t T;
    std::cin >> T;
    while (T--) {
        char str1[1024], str2[1024];
        std::cin >> str1 >> str2;
        std::cout << strcmp(str1, str2) << std::endl;
    }
    return 0;
}

月份查询(指针数组)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

已知每个月份的英文单词如下,要求创建一个指针数组,数组中的每个指针指向一个月份的英文字符串,要求根据输入的月份数字输出相应的英文单词
1月 January
2月 February
3月 March
4月 April
5月 May
6月 June
7月 July
8月 August
9月 September
10月 October
11月 November
12月 December

输入

第一行输入t表示t个测试实例
接着每行输入一个月份的数字
依次输入t行

输出

每行输出相应的月份的字符串,若没有这个月份的单词,输出error

样例输入

3
5
11
15

样例输出

May
November
error

提示

解决方案

#include <iostream>

int main() {
    const char *calendar[] = {"January", "February", "March",
                              "April", "May", "June",
                              "July", "August", "September",
                              "October", "November", "December"};
    size_t T;
    std::cin >> T;
    while (T--) {
        unsigned int month;
        std::cin >> month;
        if (1 <= month && month <= 12) {
            std::cout << calendar[month - 1] << std::endl;
        } else {
            std::cout << "error" << std::endl;
        }
    }
    return 0;
}

货币兑换(指针与常量)

时间限制: 1 Sec 内存限制: 128 MB

题目描述

设定以下汇率常量
美元汇率为6.2619,表示1美元兑换6.2619元人民币
欧元汇率为6.6744,表示1欧元兑换6.6744元人民币
日元汇率为0.0516,表示1元日元兑换0.0516元人民币
港币汇率为0.8065,表示1元港币币兑换0.8065元人民币
定义一个常量指针,根据需求指针指向不同的汇率,然后计算出各种货币兑换为人民币的数量
要求:不能直接使用汇率常量进行计算,必须使用常量指针,只能使用一个指针

输入

输入一个t表示有t个测试实例
每行先输入一个字母,表示货币类型,然后再输入一个数字(正浮点数),表示货币数量
D表示美元,E表示欧元,Y表示日圆,H表示港币
依次输入t行

输出

每行输出兑换后的人民币数量,保留4位小数
在C++中,输出指定精度的参考代码如下:

#include <iostream>
#include <iomanip> //必须包含这个头文件

using namespace std;

void main( )
{
  double a =3.141596;
  cout<<fixed<<setprecision(3)<<a<<endl;  //输出小数点后3位
}

样例输入

4
Y 10000
D 88.3
H 200
E 73.1

样例输出

516.0000
552.9258
161.3000
487.8986

提示

解决方案

#include <iostream>
#include <iomanip>

const double USD_CNY = 6.2619, EUR_CNY = 6.6744, JPY_CNY = 0.0516, HKD_CNY = 0.8065;

int main() {
    size_t T;
    std::cin >> T;
    const double *exchange_rate = nullptr;
    while (T--) {
        char type;
        double money;
        std::cin >> type >> money;
        switch (type) {
            case 'D':
                exchange_rate = &USD_CNY;
                break;
            case 'E':
                exchange_rate = &EUR_CNY;
                break;
            case 'Y':
                exchange_rate = &JPY_CNY;
                break;
            case 'H':
                exchange_rate = &HKD_CNY;
                break;
            default:
                exit(-1);
        }
        std::cout << std::fixed << std::setprecision(4) << (money * *exchange_rate) << std::endl;
    }
    return 0;
}