問題描述:
題目背景
NCLNCLNCL是一家專門從事計算器改良與升級的實驗室,最近該實驗室收到了某公司所委託的一個任務:需要在該公司某型號的計算器上加上解一元一次方程的功能。實驗室將這個任務交給了一個剛進入的新手ZL先生。
題目描述
爲了很好的完成這個任務,ZLZLZL先生首先研究了一些一元一次方程的實例:
4+3x=84+3x=84+3x=8
6a−5+1=2−2a6a-5+1=2-2a6a−5+1=2−2a
−5+12y=0-5+12y=0−5+12y=0
ZLZLZL先生被主管告之,在計算器上鍵入的一個一元一次方程中,只包含整數、小寫字母及+、-、=這三個數學符號(當然,符號“-”既可作減號,也可作負號)。方程中並沒有括號,也沒有除號,方程中的字母表示未知數。
你可假設對鍵入的方程的正確性的判斷是由另一個程序員在做,或者說可認爲鍵入的一元一次方程均爲合法的,且有唯一實數解。
輸入格式
一個一元一次方程。
輸出格式
解方程的結果(精確至小數點後三位)。
輸入輸出樣例
輸入 #1
6a-5+1=2-2a
輸出 #1
a=0.750
基本思路:
又碰到了與表達式解析和計算有關的題目,之前碰到的題目是計算一個表達式的值,這裏則是計算方程了。
首先我們要有一個宏觀的思路,我一看到這道題目的思路如下:
- 以=爲分隔,兩邊的式子應該用同一種方法解析出來。
- 解析的結果分爲兩種,一種是未知數的係數,還有一種就是常數項;這裏我直接用pair來返回了。
- 在得到=兩邊的返回值後,我們就可以通過簡單的除法來求解這個問題了。
現在的問題是怎麼求解這個表達式:
有兩種思路——我的是每一次處理像+1, -123a這樣的子表達式。還有一種就是每次處理一個字符,根據讀入的字符來設置各種標記字符(比如符號位啊啥的)
後面一種解法自己看luogu中的習題解答部分,我自己處理子表達式的方法如下:
- 處理第一個子表達式不帶符號位的情況(其實這個可以通過之前的初始化來搞定)
- 處理係數爲1和-1的未知數的情況,因爲這樣不顯示帶1和-1;
- 處理常數和未知數。
AC代碼:
#include<bits/stdc++.h>
using namespace std;
char alpha;
pair<int, int> Parse(string s) {
int l = 0;
int r = 0;
// 這個最好還是使用decltype,不然編譯器會給出warning
decltype(s.size()) i = 0;
while (i < s.size() && s[i] != '=') {
// 判斷符號
int sign;
if (i == 0 && (isdigit(s[i]) || isalpha(s[i]))) { // 第一個字符, 特殊情況
sign = 1;
} else if (s[i] == '+') {
sign = 1; ++i;
} else if (s[i] == '-') {
sign = -1; ++i;
}
// 獲得常數或者係數
int co = 0;
bool is_alpha = false; // 判斷是常數還是未知數的係數
bool has_digit = false;
// 碰到符號就代表一次搜索結束
while (i < s.size() && s[i] != '=' && s[i] != '-' && s[i] != '+') {
// 如果碰到字母
if (isalpha(s[i])) {
alpha = s[i];
is_alpha = true;
}
// 如果碰到數字
if (isdigit(s[i])) {
has_digit = true;
co = co * 10 + s[i] - 48;
}
++i;
}
// 後續處理
if (!has_digit) co = 1; // 如果一個數字都沒碰到,說明係數爲1
if (is_alpha) l += co * sign;
else r += co * sign;
}
return {l, r};
}
int main() {
string s;
cin >> s;
auto equal = find(s.begin(), s.end(), '=');
// 以=爲分隔,解析兩邊的字符串
pair<int, int> left = Parse({s.begin(), equal});
pair<int, int> right = Parse({++equal, s.end()});
// 獲取各種係數,方便進行計算
int a = left.first - right.first;
int b = right.second - left.second;
double result = double(b) / a;
// 輸出(注意防止-0.000這種格式出現)
if (fabs(result) == 0.000) {
printf("%c=0.000\n", alpha);
} else {
printf("%c=%.3f\n", alpha, double(b) / a);
}
return 0;
}
其他經驗:
- luogu的編譯器warning開的很高,所以你這裏int和容器內的size_type比較會有警告(隱式轉換),解決方法就是通過decltype(),讓編譯器來幫你獲得相關類型的變量(注意這裏不能用auto,因爲我們使用0來初始化的)。
- 浮點數是有-0.000這樣糟糕的東西存在的,如果想要把-0.000轉化爲0.000,可以使用fabs函數。