CCF-CSP认证考试 202309-3 梯度求解
一、题目描述(来源于截图)
二、思路解析
1.每个节点(表达式)需要同时存储:
- 在当前点的函数值
- 对目标变量的导数值
用Node<var, der>表示
2.求值过程:在计算表达式的同时对目标变量求导
3.算法流程:
- 设定目标变量
- 用栈计算后缀表达式:遇到操作符,根据是否是目标变量初始化<var, der>;遇到运算符,从栈弹出操作数,进行计算
- 最终栈顶的der就是答案
三、代码实现
#include<iostream>
#include<vector>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;typedef long long ll;
const ll MOD = 1e9 + 7;struct Node {ll var;ll der;Node(ll v=0, ll d=0) : var(v%MOD), der(d%MOD) {}
};int main()
{int n,m;cin>>n>>m;vector<string> expr;string s;while(cin>>s && s!="\n"){expr.push_back(s);}for(int i=0;i<m;i++){int target; // 目标变量cin>>target;vector<ll> point(n+1);for(int j=1;j<=n;j++){cin>>point[j]; //变量取值}stack<Node> st;for(const string& tok : expr){if(tok=="+"){Node right = st.top();st.pop();Node left = st.top();st.pop();Node res((left.var + right.var) % MOD, (left.der + right.der) % MOD);st.push(res);}else if(tok=="*"){Node right = st.top();st.pop();Node left = st.top();st.pop();Node res((left.var * right.var) % MOD, (left.var * right.der + left.der * right.var) % MOD);st.push(res);}else if(tok=="-"){Node right = st.top();st.pop();Node left = st.top();st.pop();Node res((left.var - right.var) % MOD, (left.der - right.der) % MOD);st.push(res);}else if(tok=="x"){//变量x1,x2,...xnint x = stoi(tok.substr(1)); ll der = (x==target) ? 1 : 0; // 目标变量的导数为1,其他为0st.push(Node(point[x], der)); // 变量x的取值为point[x],导数为der}else{ll num = stoll(tok); // 常量st.push(Node(num, 0));}}ll res = st.top().der;cout<<(res%MOD + MOD)%MOD<<endl;}return 0;
}
四、特殊方法解释
1.stoi ( tok . substr ( 1) ) 是将字符串转化为整数
示例:
string s1 = " 123 ";
int num1 = stoi (s1); // num1 = 123
tok . substr (1)---提取从位置1到字符串末尾的子串
对于 “x1" ---> "1"
对于 "x15" ---> "15"