UVa1661/LA4047 Equation

UVa1661/LA4047 Equation

题目链接

  本题是2007年icpc欧洲区域赛东北欧赛区的题目

题意

  输入一个后缀表达式f(x),解方程f(x)=0。表达式包含四则运算符,且x最多出现一次,表达式的字符数不超过30。保证不会出现除以常数0的情况,即至少存在一个x,使得f(x)不会除0。所谓后缀表达式,是指把运算符写在运算数的后面。例如,(4x+2)/2的后缀表达式为4x * 2 + 2 /。样例输入与输出如下表所示。

样例输入样例输出
4 X * 2 + 2 /X = -1/2
2 2 *NONE
0 2 X / *MULTIPLE

分析

  本题需要把后缀表达式转化成表达式树然后反复进行等式变换最后解出方程,输出是分数形式,要注意30个字符内的后缀表达式在计算中分子分母可能超出32位整数,因此要用64位整数。题目说“保证不会出现除以常数0的情况,即至少存在一个x,使得f(x)不会除0”说明在不含x的常数表达式运算中不会出现除以0(可以不进行运算合法性检验),但是含x的等式( 0 × f ( x ) = p / q ,    f ( x ) × 0 = p / q ,    0 ÷ f ( x ) = p / q 0\times f(x)=p/q,\;f(x)\times 0=p/q,\;0\div f(x)=p/q 0×f(x)=p/q,f(x)×0=p/q,0÷f(x)=p/q)就需要检验了: p ≠ 0 p\ne 0 p=0时无解, p = 0 p=0 p=0时有多解。

AC 代码

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

#define N 32
struct frac {
    long long p, q;
    void calc(char op, const frac& x) {
        if (op == '+') p = p*x.q + x.p*q, q *= x.q;
        else if (op == '-') p = p*x.q - x.p*q, q *= x.q;
        else if (op == '*') q *= x.q, p *= x.p;
        else q *= x.p, p *= x.q;
    }
    void print() const {
        long long g = abs(__gcd(p, q));
        if (q < 0) g = -g;
        cout << "X = " << p/g << '/' << q/g << endl;
    }
};
int s[N], l[N], r[N], n; char op[N];

bool has_x(int i) {
    if (op[i] == 'X') return true;
    if (op[i] < '0') return has_x(l[i]) || has_x(r[i]);
    return false;
}

frac calc(int i) {
    if (op[i] >='0' && op[i] <= '9') return {op[i]-'0', 1};
    frac x = calc(l[i]); x.calc(op[i], calc(r[i]));
    return x;
}

void solve(int i, frac& c) {
    if (i < 0) return;
    if (op[i] == 'X') return c.print();
    if (op[i] >= '0') cout << (c.p != (op[i]-'0') * c.q ? "NONE" : "MULTIPLE") << endl;
    else if (has_x(l[i])) {
        frac f = calc(r[i]);
        if (f.p == 0 && (op[i] == '*' || op[i] == '/')) cout << (c.p ? "NONE" : "MULTIPLE") << endl;
        else c.calc(op[i] == '*' ? '/' : (op[i] == '/' ? '*' : (op[i] == '+' ? '-' : '+')), f), solve(l[i], c);
    } else if (has_x(r[i])) {
        frac f = calc(l[i]);
        if (f.p == 0 && (op[i] == '*' || op[i] == '/')) cout << (c.p ? "NONE" : "MULTIPLE") << endl;
        else if (op[i] == '/' && c.p == 0) cout << "NONE" << endl;
        else if (op[i] == '-' || op[i] == '/') f.calc(op[i], c), solve(r[i], f);
        else c.calc(op[i] == '*' ? '/' : '-', f), solve(r[i], c);
    } else {
        frac f = calc(i); cout << (f.p * c.q != c.p * f.q ? "NONE" : "MULTIPLE") << endl;
    }
}

void solve() {
    int t = n = 0, k; frac c{0, 1};
    if (cin.peek() == '\n') cin.get();
    while ((k = cin.peek()) != '\n' && k != EOF) if (k != ' ') {
        cin >> op[n++];
        if (k >= '0') s[t++] = n-1;
        else r[n-1] = s[--t], l[n-1] = s[t-1], s[t-1] = n-1;
    } else cin.get();
    solve(n-1, c);
}

int main() {
    while (cin.peek() != EOF) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值