HNUST计算机学院23级C语言期中考试 J 题一元一次方程C++版题解

编辑人:Alant

编辑时间:2023年12月7日

题目链接

问题 J: 一元一次方程

完整题目

题目描述:

写一个C程序求一元一次方程的根。方程的基本形式如下: ax op1 b=cx op2 d

a、b、c、d均为大于1且不超过100的整数,其中a-c不等于0,op1和op2为‘+’或'-'。等式的一侧最多两项,最少一项。等号两边的px op q也可能写成q op px。另外,方程中可能有空格。

下面是几个方程的例子: 2x+2=3x+3 2 x + 2 = 4 - 3 x 2-5x = 2 2=4x 4x=2

输入:

一个一元一次方程。其中30%的数据是ax=b的形式,不会做复杂的可以只按这种方式处理。

输出:

输出如"x=root"的形式。根为整数直接输出,如果为分数则输出最简分数形式。

样例输入1

3x+2=2x+4

样例输出1

x=2

样例输入2

3-6x=6

样例输出2

x=-1/2

样例输入3

2=4x

样例输出3

x=1/2

考点解析

  1. 特殊输入:当字符串内部含有特殊字符时,应该采取什么样的策略?可以使用while(scanf("...",&...)!=EOF)的形式对特殊字符进行过滤,笔者这里采用的是getline函数

  2. 分数最简化:如何判断结果是否最简以及如何正确化简,进一步说就是如何求两数的最大公因子,可以使用辗转相除法递归求取。

注意事项

  1. 笔者并不是专业的算法爱好者,本题解仅提供一种融合面向对象思想的题解示例,希望以此抛砖引玉其中不乏不规范、不简洁、不标准以及现阶段课程未学习的用法,请各位读者见谅,必要时可借助GPT辅助理解。

  2. 本题解并未经过全面覆盖测试,可能存在并未考虑到的极端特殊情况,请各位读者慎重参考。

核心思想

     将方程式化为形如ax=b的格式

代码流程

  1. 对输入的方程式进行数据预处理(即删除空格)

  2. 在字符串中搜索下一个“数据项”的开始、结束下标(数据项:形如x5x-3x678-48的子串)并更新

  3. 提取每一个数据项包含的数据

  4. 如果该数据是变量的系数,则放入a;如果是常数,则放入b(如果跨越=会对符号产生变化)

  5. 重复2-4直至所有数据项均被处理

完整代码

#include <iostream>
​
using namespace std;
​
// 在字符串s中寻找下一个数据项的开始、结束下标
void nextData(int* start, int* end, string s) {
    for (*end = *start; *end <= s.length(); (*end)++) {
        if (s[*end] == '=') {
            (*end)--;
            return;
        }
        if (*end + 1 >= s.length() || s[*end + 1] == '+' || s[*end + 1] == '-') {
            return;
        }
    }
}
​
// 提取每一个数据项包含的数据
int getNumFromData(string s) {
    int symbol = s[0] == '-' ? -1 : 1;
    int num = 0;
    if (s[0] == '-' && s[1] == 'x')return -1;
    if (s[0] == 'x' || (s[0] == '+' && s[1] == 'x'))return 1;
    for (int i = 0; i < s.length(); i++) {
        if (s[i] < '0' || s[i] > '9')continue;
        else {
            num = num * 10 + int(s[i] - '0');
        }
    }
    return num * symbol;
}
​
// 计算a、b的最大公因子
int getMaxCommonFactor(int a, int b) {
    int commonFactor = 1;
    for (int i = 2; i <= min(a, b); i++) {
        if (a % i == 0 && b % i == 0)commonFactor = i;
    }
    return commonFactor;
}
​
// 打印结果,该函数还包含了化简的业务功能
void printAns(int a, int b) {
    int maxCommonFactor = getMaxCommonFactor(abs(a), abs(b));
    a /= maxCommonFactor;
    b /= maxCommonFactor;
    if (a < 0 && b < 0) {
        a *= -1;
        b *= -1;
    }
    if (a == 1) {
        cout << "x=" << b;
        return;
    }
    if (b == 0) {
        cout << "x=0";
        return;
    }
    if (b < a) {
        if (a * b > 0) {
            cout << "x=" << to_string(abs(b)) + "/" + to_string(abs(a));
        } else {
            cout << "x=-" << to_string(abs(b)) + "/" + to_string(abs(a));
        }
    } else {
        if (a * b > 0) {
            if (b % a == 0)cout << "x=" + to_string(b / a);
            else cout << "x=" << to_string(b) << "/" << to_string(a);
        } else {
            if (b % a == 0)cout << "x=-" + to_string(b / a);
            else cout << "x=-" << to_string(abs(b)) << "/" << to_string(abs(a));
        }
    }
}
​
// 主函数
int main() {
    string _s;
    getline(cin, _s);
    string s;
    for (int i = 0; i < _s.length(); i++) {
        if (_s[i] != ' ') {
            s += _s[i];
        }
    }
    int a = 0, b = 0;
    int start = 0, end = 999999;
    int equal = 1;
    while (s[equal] != '=')equal++;
    while (start < s.length()) {
        nextData(&start, &end, s);
        int num = getNumFromData(s.substr(start, end - start + 1));
        if (s[end] == 'x' && start < equal)a += num;
        else if (s[end] == 'x' && start > equal)a += num * -1;
        else if (s[end] != 'x' && start > equal)b += num;
        else if (s[end] != 'x' && start < equal)b += num * -1;
        start = end + 1;
        if (start < s.length() && s[start] == '=')start++;
    }
    printAns(a, b);
    return 0;
}

更多测试数据

99+6x=5+2x

16+3x = 4 +12x

5+2x=6x+99

5x=100

8x=12

5+3x = 2x-3

5+ 3 x = 2 x- 3

-999=x

x=0

扩展思考

  1. op如果包含*、/,如何求解?

  2. 如果是二元一次方程,如何求解?

  3. 如果是多元一次方程组,如何求解?

友情链接

Homemade Strategic Office Capability 国产战略办公能力

青年大学习之高效使用办公软件(持续更新Word、PPT、Excel的使用技巧,不定期分享免费PPT模板)

详情请至gitee搜索开源库Alant/HSOC

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值