当前位置:首页 > 洛谷题解 > 洛谷P1572题解:分数运算的奥秘,新手也能看懂的超详细教程

洛谷P1572题解:分数运算的奥秘,新手也能看懂的超详细教程

2天前洛谷题解60

截图未命名.jpg 洛谷P1572题解:分数运算的奥秘,新手也能看懂的超详细教程 字符串解析 C++编程 算法 洛谷题解 第1张

一、问题分析

洛谷P1572题目要求我们处理一个包含分数加减运算的字符串表达式,最终输出最简分数结果。我们需要解决以下几个关键问题:

  1. 如何从字符串中解析出各个分数

  2. 如何处理加减运算符

  3. 如何进行分数的加减运算

  4. 如何化简最终结果

二、详细技术讲解

1. 分数表示与运算

我们使用一个简单的结构体Fraction来表示分数,包含分子和分母两个成员变量。结构体中实现了两个关键方法:

  • simplify(): 用于化简分数,通过计算分子分母的最大公约数,并将分数化为最简形式

  • operator+: 重载加法运算符,实现分数的加法运算

2. 字符串解析

解析输入字符串是本题的关键难点。我们需要处理以下几种情况:

  1. 正负号的处理:每个分数可能有自己的正负号

  2. 分子和分母的分离:通过'/'字符分隔

  3. 运算符的识别:'+'或'-'符号

解析过程采用逐个字符扫描的方式:

  • 首先处理可能的符号位

  • 然后读取数字部分作为分子

  • 如果遇到'/',则继续读取分母

  • 否则视为整数(分母为1)

  • 最后记录运算符

3. 计算过程

计算过程相对简单:

  1. 初始化结果为第一个分数

  2. 根据运算符决定后续分数是加还是减

  3. 逐个进行分数运算

  4. 每次运算后自动化简结果

4. 结果输出

最终结果需要根据分母是否为1决定输出形式:

  • 分母为1:输出整数形式

  • 否则:输出分数形式

三、完整代码

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

// 计算最大公约数
int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

// 分数结构体
struct Fraction {
    int numerator;   // 分子
    int denominator; // 分母
    
    // 化简分数
    void simplify() {
        int common = gcd(abs(numerator), abs(denominator));
        numerator /= common;
        denominator /= common;
        // 确保分母为正
        if (denominator < 0) {
            numerator *= -1;
            denominator *= -1;
        }
    }
    
    // 分数加法
    Fraction operator+(const Fraction& other) const {
        Fraction result;
        result.numerator = numerator * other.denominator + other.numerator * denominator;
        result.denominator = denominator * other.denominator;
        result.simplify();
        return result;
    }
};

int main() {
    string s;
    getline(cin, s);
    
    vector<Fraction> fractions;
    vector<char> operators;
    
    // 解析字符串
    int i = 0;
    while (i < s.size()) {
        // 解析分子
        int sign = 1;
        if (s[i] == '-') {
            sign = -1;
            i++;
        } else if (s[i] == '+') {
            i++;
        }
        
        int num = 0;
        while (i < s.size() && isdigit(s[i])) {
            num = num * 10 + (s[i] - '0');
            i++;
        }
        num *= sign;
        
        // 解析分母
        if (i < s.size() && s[i] == '/') {
            i++;
            int den = 0;
            while (i < s.size() && isdigit(s[i])) {
                den = den * 10 + (s[i] - '0');
                i++;
            }
            fractions.push_back({num, den});
        } else {
            // 整数视为分母为1的分数
            fractions.push_back({num, 1});
        }
        
        // 记录运算符
        if (i < s.size() && (s[i] == '+' || s[i] == '-')) {
            operators.push_back(s[i]);
            i++;
        }
    }
    
    // 计算结果
    Fraction result = fractions[0];
    for (int j = 0; j < operators.size(); j++) {
        Fraction next = fractions[j + 1];
        if (operators[j] == '-') {
            next.numerator *= -1;
        }
        result = result + next;
    }
    
    // 输出结果
    if (result.denominator == 1) {
        cout << result.numerator << endl;
    } else {
        cout << result.numerator << "/" << result.denominator << endl;
    }
    
    return 0;
}

四、常见问题解答

Q: 如何处理连续的运算符?
A: 题目保证输入合法,不会出现连续的运算符。

Q: 如何处理分母为0的情况?
A: 题目保证输入合法,不会出现分母为0的情况。

Q: 为什么要在化简函数中处理分母的符号?
A: 这是为了统一分数的表示形式,确保分母始终为正数,便于比较和后续处理。

五、扩展思考

  1. 如何扩展支持乘除法运算?

  2. 如何处理带括号的表达式?

  3. 如何支持混合数(如3又1/2)的输入?

六、总结

通过这道题目,我们学习了:

  • 字符串解析的技巧

  • 分数运算的原理

  • 运算符重载的应用

  • 代码结构化的设计方法

掌握这些基础知识对于解决更复杂的计算问题至关重要。


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。