梯度求解 第31次CCF-CSP计算机软件能力认证
大佬题解
如果你有深度学习基础的话,那么这道题就很容易想到了,根据深度学习的计算规则,想要计算梯度,先要构建一张计算图,使用二叉树实现,因为已经给了逆波兰表达式,使用栈就可以构建出计算图(二叉树),然后forward正向传播,正向传播的目的是计算出每个结点对应的中间值用来反向传播使用,然后backward反向传播,递归求解到叶子结点然后返回即可。
AC代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 1e9 + 7;/*----------------- 结点 -----------------*/
struct Node {string op;int l = -1, r = -1;Node() {}Node(string o) :op(std::move(o)) {}Node(string o, int L, int R) :op(std::move(o)), l(L), r(R) {}
};
vector<Node> tree;/*----------------- 工具 -----------------*/
inline bool isOp(const string& s) { return s == "+" || s == "-" || s == "*" || s == "/"; }
inline bool isNumber(const string& s) { return !s.empty() && (isdigit(s[0]) || (s[0] == '-' && s.size() > 1)); }
ll mod_add(ll a, ll b) { a += b; if (a >= MOD) a -= MOD; if (a < 0) a += MOD; return a; }
ll mod_mul(ll a, ll b) { return (a % MOD) * (b % MOD) % MOD; }/*----------------- build -----------------*/
int build_tree(const vector<string>& pf) {stack<int> st;for (const string& tok : pf) {if (isOp(tok)) {int r = st.top(); st.pop();int l = st.top(); st.pop();int id = tree.size();tree.emplace_back(tok, l, r);st.push(id);}else {int id = tree.size();tree.emplace_back(tok);st.push(id);}}return st.top();
}/*----------------- forward -----------------*/
ll eval(int u, vector<ll>& val, const vector<ll>& varVal) {if (val[u] != -1) return val[u];const Node& nd = tree[u];if (nd.l == -1) { // 叶子if (isNumber(nd.op))val[u] = (stoll(nd.op) % MOD + MOD) % MOD;else {int idx = stoi(nd.op.substr(1)) - 1; // 关键修正 ↓↓↓val[u] = varVal[idx];}}else {ll L = eval(nd.l, val, varVal);ll R = eval(nd.r, val, varVal);if (nd.op == "+") val[u] = mod_add(L, R);else if (nd.op == "-") val[u] = mod_add(L, -R);else if (nd.op == "*") val[u] = mod_mul(L, R);}return val[u];
}/*----------------- backward -----------------*/
ll backward(int u, int target, const vector<ll>& val) {const Node& nd = tree[u];if (nd.l == -1) {return (!isNumber(nd.op) && (stoi(nd.op.substr(1)) - 1) == target) ? 1 : 0; // 关键修正 ↓↓↓}ll dL = backward(nd.l, target, val);ll dR = backward(nd.r, target, val);ll L = val[nd.l];ll R = val[nd.r];if (nd.op == "+") return mod_add(dL, dR);if (nd.op == "-") return mod_add(dL, -dR);if (nd.op == "*") return mod_add(mod_mul(dL, R), mod_mul(L, dR));return 0;
}/*----------------- main -----------------*/
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n, m;cin >> n >> m;cin.ignore();string line, tok;getline(cin, line);istringstream iss(line);vector<string> postfix;while (iss >> tok) postfix.push_back(tok);tree.clear();int root = build_tree(postfix);for (int q = 0; q < m; ++q) {int idx; cin >> idx; --idx; // 改成 0‑basevector<ll> varVal(n);for (int i = 0; i < n; ++i) {cin >> varVal[i];varVal[i] = (varVal[i] % MOD + MOD) % MOD;}vector<ll> val(tree.size(), -1);eval(root, val, varVal);cout << backward(root, idx, val) % MOD << '\n';}return 0;
}