化学方程式配平(第33次CCF计算机软件能力认证 第3题)题解 高斯消元
题目链接:https://www.acwing.com/problem/content/5724/
前置练习:P3389 【模板】高斯消元法
解题思路:
首先根据字符串构造矩阵。
假设构造的是一个 \(n \times m\) 的矩阵。
很明显,秩最大是 \(\min(n,m)\)。
要求 秩 \(\lt m\) 时输出 Y,秩 \(= m\) 时输出 N(秩 不可能大于 \(m\))。
所以,当 \(n \lt m\) 时,秩(\(\min(n,m)\))肯定小于 \(m\),直接输出 Y 即可。
当 \(n \ge m\) 时,我们调 高斯消元 模板即可(只不过只需要考虑前 \(m\) 行)。
处理到第 \(i\) 行时,如果第 \(i \sim n\) 列全为 \(0\),则这一行 无解 或 无数解。秩减小 \(1\)。\(\Rightarrow\) 本来每一行都有解是秩为 \(m\),现在秩减小 \(1\) 最大也是 \(m-1\) 了,秩肯定小于 \(m\),可以确定 Y。
如果最终算出来的秩为 \(m\),则输出 NO。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
int T, n, m;
double a[45][45];
map<string, int> mp[45];
set<string> st;
void init() {
for (int i = 1; i <= 40; i++) {
mp[i].clear();
fill(a[i]+1, a[i]+41, 0);
}
st.clear();
n = 0;
}
void cal(string &s, int p) {
for (int i = 0; i < s.size(); ) {
string tmp;
int cnt = 0;
while (isalpha(s[i]))
tmp += s[i++];
while (i < s.size() && isdigit(s[i])) {
cnt = cnt * 10 + s[i] - '0';
i++;
}
mp[p][tmp] = cnt;
st.insert(tmp);
}
}
bool gauss(int n, int m) {
if (n < m)
return true;
for (int i = 1; i <= m; i++) {
int p = -1;
for (int j = i; j <= n; j++) {
if (abs(a[j][i]) > eps) {
p = j;
break;
}
}
if (p == -1)
return true;
if (p != i) { // 交换第i行和第p行第 i..n 列的元素
for (int j = i; j <= m; j++)
swap(a[i][j], a[p][j]);
}
for (int j = m; j >= i; j--)
a[i][j] /= a[i][i];
for (int j = 1; j <= n; j++) {
if (j == i || abs(a[j][i]) < eps)
continue;
double bei = a[j][i];
for (int k = i; k <= m; k++) // 将a[j][i..n] = 0
a[j][k] -= bei * a[i][k];
}
}
return false;
}
int main() {
cin >> T;
while (T--) {
init();
cin >> m;
for (int i = 1; i <= m; i++) {
string s;
cin >> s;
cal(s, i);
}
for (auto &s : st) {
n++;
for (int i = 1; i <= m; i++) {
a[n][i] = mp[i][s];
}
}
if (gauss(n, m))
cout << "Y" << endl;
else
cout << "N" << endl;
}
return 0;
}
浙公网安备 33010602011771号