化学方程式配平(第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;
}
posted @ 2025-11-28 11:29  quanjun  阅读(6)  评论(0)    收藏  举报