逐项扫描一元一次方程,左半边按原符号、右半边变号累加,合并成 ax+b=0 后解 x=-b/a 保留三位小数。
OJ: roj
题目 ID: 3498
难度:普及
标签:模拟字符串解析
创建: 2026-10-02 03:11
更新: 2026-10-06 12:08
题目描述
给定一个一元一次方程,只包含整数、一个小写字母(未知数)及 +、-、= 三种符号,没有括号和除号;- 既可作减号也可作负号,形如 a 的项省略了系数 1。方程合法且有唯一实数解,求这个解,输出格式为 未知数=值,值精确到小数点后三位。
例如输入 6a-5+1=2-2a,输出 a=0.750。
思路
把 = 右边逐项变号移到左边,合并同类项得 -0.000。
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 03:11
# update_at: 2026-10-02 03:11
import re
import sys
TERM = re.compile(r'[+-]?(?:\d+[a-z]?|[a-z])') # 一项:可选符号 + 数字(可带字母)或单个字母
def balance(side: str, direction: int) -> tuple[int, int]:
"""把半边的每一项移到方程左边:返回(未知数系数和,常数和),direction 表示这半边的正负号。"""
coef = const = 0
for term in TERM.findall(side):
sign = -1 if term[0] == '-' else 1 # 项首的 + / - 就是这一项的符号
body = term.lstrip('+-')
if body[-1].isalpha(): # 未知数项:`a`、`-a` 省略了系数 1
coef += sign * direction * int(body[:-1] or '1')
else: # 常数项
const += sign * direction * int(body)
return coef, const
def solve() -> None:
data = iter(sys.stdin.read().split()) # 整行方程不含空格,按空白切开只有一个 token
equation = next(data)
left, right = equation.split('=')
coef, const = balance(left, 1)
rcoef, rconst = balance(right, -1) # 右半边整体移项到左边
coef, const = coef + rcoef, const + rconst
answer = -const / coef
if answer == 0:
answer = 0.0 # 抵消 -0.0,避免输出 -0.000
name = re.search(r'[a-z]', equation).group() # 方程里唯一的小写字母就是未知数
print(f'{name}={answer:.3f}')
if __name__ == '__main__':
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 12:08
* update_at: 2026-10-06 12:08
*/
// 解一元一次方程:无括号,只有整数、一个未知数字母和 + - = 三种符号。
// 思路:把 = 右边整体移到左边(逐项变号),合并同类项得 coef*x + const = 0,
// 答案 x = -const / coef。
#include <cstdio>
#include <cstring>
typedef long long ll;
char s[1005]; // 存整个方程
ll len; // 方程长度
ll pos; // 当前解析到的下标
ll coef; // 未知数系数和(移项后)
ll cst; // 常数项和(移项后)
char name; // 未知数字母
// 判断是否字母(未知数)
bool is_alpha(char c) {
return c >= 'a' && c <= 'z';
}
// 解析一项:该项必带符号(用 side 修正右半边方向),累加进 coef / cst
// side:左半边为 1,右半边为 -1(相当于右边整体乘 -1 移到左边)
void parse_term(ll side) {
ll sign = 1; // 这一项的符号
if (s[pos] == '-') {
sign = -1;
pos++;
} else if (s[pos] == '+') {
pos++;
}
// 项体:要么是数字串(后面可跟字母),要么是单个字母(省略系数 1)
ll num = 0;
bool has_digit = false;
while (pos < len && s[pos] >= '0' && s[pos] <= '9') {
num = num * 10 + (s[pos] - '0');
has_digit = true;
pos++;
}
if (pos < len && is_alpha(s[pos])) { // 未知数项:6a / a / -a
if (!has_digit) num = 1; // 省略了系数 1
coef += side * sign * num;
if (name == 0) name = s[pos]; // 记下未知数字母
pos++;
} else { // 常数项
cst += side * sign * num;
}
}
int main() {
scanf("%s", s);
len = strlen(s);
pos = 0;
coef = 0;
cst = 0;
name = 0;
// 左半边:遇到 = 停
while (pos < len && s[pos] != '=') parse_term(1);
pos++; // 跳过 =
// 右半边:side = -1 表示移项到左边要变号
while (pos < len) parse_term(-1);
// 此时方程化为 coef * x + cst = 0,x = -cst / coef(ll 除法转 double 隐式完成)
double ans = -1.0 * cst / coef;
if (ans == 0.0) ans = 0.0; // 消除 -0.000 的情况
printf("%c=%.3f\n", name, ans);
return 0;
}