CSP-31补题日记--梯度求解

202309-3-梯度求解

题目链接

http://118.190.20.162/view.page?gpid=T173

最近刚刚在上数据结构二叉树
跟这道题真的是强相关
然后在就是涉及到了数学求导
这基本上是我复学两个月做的最久的题了
感觉做完这道题对栈和二叉树理解比以前清晰了很多
不摆了
上代码

** 题目思路:
题意是给我们一个后缀表达式
显然,我们就可以写出这个表达式
那么怎么来实现求导呢?
不妨讨论,常数求导equal 0;
偏导的未知数求导equal 1 ;
其他符号 a (±)b求导equal
a导 (±
)b导
这样我们是不是就可以递归实现求导呢!
分析可得做题步骤
1:利用栈来建立二叉树存表达式,因为是后缀表示,所以唯一可以考虑只使用一个栈
2:dfs遍历求导,并将结果存在二叉树里面
3:带入计算,最重要的是要取模运算(可恶)
**

/*
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef  pair<int,int> pi ;
#define if1(x) for(int i =1 ;i<=x;i++)
#define if0(x) for(int i = 0;i<x;i++)
#define jf0(x) for(int j = 0;j<x;j++)
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int m,n,idx;
struct node{
   int vis_num;//1表示他是数字,0表示他是未知数,
   //2表示他是操作符号,3表示求偏导的未知数
   int x;
   ll val;
   char op;
   //既然要存树,那么不妨使用数组来存树
   int fa;
   int l;
   int r;
   int myself;
};
node tree[550];
//vector<node> tree;
vector<int> xs(200);
int xans;//存储偏导未知数的位置
string s;
node retu0,retux,retu1;
stack<node> sta_num;
void push_num(string x){
   int num = stoi(x);
   node te = *new(node);
   te.vis_num=1;te.val =num;
   te.fa = te.l = te.r =-1;
   tree[idx] = te;
   te.myself = idx++;
   // tree.push_back(te)
   sta_num.push(te);

}
node dfs(node root){
//分析讨论vis的三种状态
//当节点未数字时,求导直接返回0;
   if(root.vis_num==1) return retu0;//数字求导的结果就是0

//当节点遇到x时,求导时应该分两种情况判断
   else if(root.vis_num==0){
//若x是我们所求的偏导,我们就应该返回retux
       if(root.x==xans) return retu1;   
//若x不是是我们所求未知数的偏导,
//则我们应该视为常数我们就应该返回0
       else return retu0;
   }

//ok写到这里,应该是此代码最复杂的一部分
//(a*b)求导=a导*b+b导*a
   else if(root.op=='*'){
       //注意,我们还应该给新分配的三个节点一个idx来存下来
       node rnode = *new(node);
       node lnode = *new(node);
       node father = *new(node);
       // tree.push_back(rnode);
       // tree.push_back(lnode);
       // tree.push_back(father);
       //先写一下左边巴
       lnode.vis_num=2;
       lnode.op = '*';
       lnode.l = root.l;
       lnode.r = dfs(tree[root.r]).myself;
       lnode.fa = father.myself;
       tree[idx]  = lnode;
       lnode.myself = idx++;
       


       //写右边
       rnode.vis_num = 2;
       rnode.op='*';
       rnode.r = root.r;
       rnode.l = dfs(tree[root.l]).myself;
       rnode.fa = father.myself;

       tree[idx] = rnode;
       rnode.myself = idx++;
       
       //写她爹
       father.vis_num = 2;
       father.op = '+';
       father.r = rnode.myself;
       father.l = lnode.myself;
       tree[idx] = father;
       father.myself = idx++;
       return father;



   }
   //op是+-的时候,很明显就是l导+-r导
   else{
       node father = *new(node);
       father.fa = father.l = father.r = -1;
       father.vis_num=2;
       father.op = root.op;
       father.r = dfs(tree[root.r]).myself;
       father.l = dfs(tree[root.l]).myself;
       father.myself = idx;
       tree[idx++] = father;
       return father;
   }
}
void init(){
   retu0.fa = retu0.l=retu0.r=-1;
   retu0.vis_num=1;
   retu0.val=0;
   retu0.myself = -2;//特殊给0;

   retu1.fa = retu1.r=retu1.l=-1;
   retu1.vis_num=1;//特殊给一个。
   retu1.val = 1;
   retu1.myself=-4;

   retux.fa = retux.l = retux.r=-1;
   retux.vis_num = 3;
   retux.myself = -3;//特殊给未知数的下标;
   return;
}
ll caculate(node root){
   if(root.vis_num==1)return root.val;
   //遇到计算偏导x时
   else if(root.vis_num==3)return xs[xans];
   //通过处理,我们可以肯定dfs后再无vis——num=0,就是未知数的情况了
   //写在后面,根本特殊处理不了一点点
   //因为它有些是在*+-里面的未知数
   else if(root.vis_num==0) return xs[root.x];
   else{
       //现在就是开始运算了,
       ll a , b ;
       if(root.l<0){
           if(root.l == -2) a=0;
           else if(root.l == -3) a = xs[xans];
           else if(root.l==-4) a = 1;
       }
       else a = caculate(tree[root.l]);
       if(root.r<0){
           if(root.r == -2) b=0;
           else if(root.r == -3) b = xs[xans];
           else if(root.r== -4) b = 1;
       }
       else b = caculate(tree[root.r]);

       if(root.op=='+'){
           return ((a%mod)+(b%mod))%mod;
       }else if(root.op=='-'){
           return ((a%mod)-(b%mod))%mod;
       }
       else{
           return (a%mod)*(b%mod)%mod;
       }
   }
}
void solve(){
   init();
   cin>>n>>m;//n-自变量,m-求偏导的次数
   getchar();
   getline(cin,s);
   int le = s.size();
   if0(le){

       //split 操作
       int j = i+1;
       while(s[j]!=' '&&j<le)j++;
       string temp = s.substr(i,j-i);

       //为数字
       if((temp[0]>='0'&&temp[0]<='9')||temp[0]=='-'&&j>i+1){
           push_num(temp);
       }

       //为未知数的时候
       else if(temp[0]=='x'){
           int te = stoi(temp.substr(1,temp.size()-1));
           node tt = *new(node);
           tt.vis_num=0;tt.x=te;
           tt.fa = tt.l = tt.r =-1;
           tree[idx]=tt;
           tt.myself = idx++;
           //tree.push_back(tt);
           sta_num.push(tt);
       }


       else {
           //通过简单分析哈,我们在遇到操作符号的时候可以更新
           //一下树,不如直接存树?
           node te = *new(node);
           te.vis_num=2;
           te.op = temp[0];
           te.fa =-1;
           te.r = sta_num.top().myself;
           sta_num.pop();
           te.l = sta_num.top().myself;
           sta_num.pop();
           tree[idx] = te;
           te.myself = idx++;
           sta_num.push(te);

       }
       
       i=j;//1st--bug,因为for它自己已经加一辣
   }

   //存树结束
   if0(m){
       int temp_idx = idx;//考虑后面我们可以释放一波内存
       //既然写的这么认真了,那么在内存方面也可以考虑变得更优。
       cin>>xans;//读入偏导x
       jf0(n)cin>>xs[j+1];//读入x的赋值,因为我们在建树的时候
       //我们直接存的是x的下标,所以未便于调用,从1开始存。
       //简单讨论,最后栈的唯一元素便是根节点。
       node ans = dfs(sta_num.top());
       ll res = caculate(ans)%mod;
       res = (res+mod)%mod;
       cout<<res<<endl;
       idx = temp_idx;
   }

}
int main(){
   solve();
  // getchar();
   
   return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/116128.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32HAL-完全解耦面向对象思维的架构-时间轮片法使用(timeslice)

目录 概述 一、开发环境 二、STM32CubeMx配置 三、编码 四、运行结果 五、代码解释 六、总结 概述 timeslice是一个时间片轮询框架&#xff0c;完全解耦的时间片轮询框架&#xff0c;非常适合裸机单片机引用。接下来将该框架移植到stm32单片机运行&#xff0c;单片机…

Git命令大全

Git命令大全 1、初始化本地仓库 git init <directory><>意思是可选的&#xff0c;如果不指定&#xff0c;将使用当前目录。 2.克隆一个远程仓库 git clone <url>3.添加文件到暂存区 git add <file>要添加当前目录中的所有文件&#xff0c;请使用.…

Http代理与socks5代理有何区别?如何选择?(一)

了解SOCKS和HTTP代理之间的区别对于优化您的在线活动至关重要&#xff0c;无论您是技术娴熟的个人、现代互联网用户还是企业所有者。在使用代理IP时&#xff0c;您需要先了解这两种协议之间的不同。 一、了解HTTP代理 HTTP&#xff08;超文本传输协议&#xff09;代理专门设计…

C语言_动态内存管理

文章目录 一.为什么存在动态内存分配二.动态内存函数的介绍2.1 malloc 和 free2.2 calloc原型如下 2.3 realloc函数模型如下 三.常见的动态内存错误3.1 对NULL的解引用操作3.2对动态开辟空间的越界访问3.3非动态开辟内存使用free释放3.4使用free释放一块动态开辟内存的一部分3.…

数据结构(超详细讲解!!)第二十节 数组

1.定义 1.概念 相同类型的数据元素的集合。 记作&#xff1a;A(A0,A1,…,Am-1) 二维数组可看作是每个数据元素都是相同类型的一维数组的一维数组。多维数组依此类推。 二维数组是数据元素为线性表的线性表。 A(A0&#xff0c;A1&#xff0c;……&#xff0c;An-1) 其中…

JAVA 实现PDF转图片(spire.pdf.free版)

1.引入jar包 导入方法1&#xff1a; 手动引入。将Free Spire.PDF for Java下载到本地&#xff0c;解压&#xff0c;找到lib文件夹下的Spire.PDF.jar文件。在IDEA中打开如下界面&#xff0c;将本地路径中的jar文件引入Java程序&#xff1a; 导入方法2&#xff1a;如果您想通过…

uinapp微信小程序隐私政策授权

&#x1f680; 隐私弹窗效果图&#xff1a; 1、启用隐私相关功能在manifest.json文件中配置 usePrivacyCheck: true "mp-weixin" : {"__usePrivacyCheck__" : true, },2、创建组件 <template><view><!-- 隐私政策弹窗 --><uni-popu…

高德地图撒点组件

一、引入amap地图库 - public/index.html <script type"text/javascript">window._AMapSecurityConfig {securityJsCode: 地图密钥 }</script><scripttype"text/javascript"src"https://webapi.amap.com/maps?v1.4.8&key111111…

回归预测 | Matlab实现MPA-BP海洋捕食者算法优化BP神经网络多变量回归预测

回归预测 | Matlab实现MPA-BP海洋捕食者算法优化BP神经网络多变量回归预测 目录 回归预测 | Matlab实现MPA-BP海洋捕食者算法优化BP神经网络多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现MPA-BP海洋捕食者算法优化BP神经网络多变量回归预测&…

基于单片机的自动感应门设计

博主主页&#xff1a;单片机辅导设计 博主简介&#xff1a;专注单片机技术领域和毕业设计项目。 主要内容&#xff1a;毕业设计、简历模板、学习资料、技术咨询。 文章目录 主要介绍一、自动感应门设计的功能概述二、系统总体方案2.1系统的总体计划2.2元器件的介绍2.2.1单片机的…

【程序员日记】一行console.log引发的血案

▒ 目录 ▒ &#x1f6eb; 导读需求开发环境 1️⃣ 艰难的排查过程1. 程序闪退2. 确定为内存泄漏3. 误入歧途4. 二分法注释代码5. 猿脑猜想 2️⃣ 排查procexp.exePerformance 和 Memory 3️⃣ 剔除生产环境中的console.logwebpack插件terser-webpack-plugin &#x1f6ec; 文章…

VX-3R APRS发射试验

VX-3R本身是不带APRS功能的&#xff0c;不过可能通过外加TNC实现APRS功能。 有大佬已经用Arduino实现了相应的发射功能&#xff1a; https://github.com/handiko/Arduino-APRS 我要做的&#xff0c;就是简单修改一下代码&#xff0c;做一个转接板。 YEASU官方没有给出VX-3R的音…

ch0_OSI 七层网络协议介绍

目录 概述 1、三网融合的概念 三网&#xff1a;电信网络、有线电视网络、计算机网络 概念&#xff1a;把上述三种网络融合成一种网络 2、计算机网络的定义、分类 定义&#xff1a;计算机网络是将地理位置不同的独立计算机系统&#xff0c;通过传输介质链接起来&#xff0c…

7-4 修理牧场 分数 15

#include<iostream> #include<queue> using namespace std; #define maxn 10005int main() {int n 0, data 0;cin >> n;//建小堆: //上调建堆中用greater: 父大子小 父子交换 小的上去 大的下去 priority_queue<int, vector<int>, greater<int…

vue+asp.net Web api前后端分离项目发布部署

一、前后端项目介绍 1.前端项目是使用vue脚手架进行创建的。 脚手架版本&#xff1a;vue/cli 5.0.8 编译器版本&#xff1a;vs code 1.82.2 2.后端是一个asp.net Core Web API 项目 后端框架版本&#xff1a;.NET 6.0 编译器版本&#xff1a;vs 2022 二、发布部署步骤 第…

静态链表的定义与实现(数据结构与算法)

1. 静态链表 用数组的方式实现的链表 单链表&#xff1a; 各个结点在内存中星罗棋布、散落天涯 静态链表&#xff1a;分配一整片连续的内存空间&#xff0c; 各个结点集中安置。 1.1 静态链表的优点 不需要像动态链表那样频繁地进行内存分配和释放&#xff0c;可以节省内存…

缺陷之灵魂操作bug

一、前言 正常来说&#xff0c;我们在测试缺陷的时候都是按照case来测试的&#xff0c;但是有些场景&#xff0c;例如说发散思维这种场景&#xff0c;就会找到一些比较不太正常、不好复现的缺陷&#xff0c;然后如果要辅助研发修复&#xff0c;就会极为痛苦。 二、场景描述 大…

mysql迁移data目录(Linux-Centos)

随着时间的推移&#xff0c;mysql的数据量越越大&#xff0c;使用yum默认安装的目录为系统盘 /var/lib/mysql&#xff0c;现重新挂载了一个硬盘&#xff0c;需要做数据目录的迁移到 /mnt/data/。以解决占用系统盘过高情况。 1.强烈建议这种操作。镜像一个一样的Centos系统&…

掌控你的Mac性能:System Dashboard Pro,一款专业的系统监视器

作为Mac用户&#xff0c;你是否曾经想要更好地了解你的电脑性能&#xff0c;以便优化其运行&#xff1f;是否想要实时监控系统状态&#xff0c;以便及时发现并解决问题&#xff1f;如果你有这样的需求&#xff0c;那么System Dashboard Pro就是你的不二之选。 System Dashboar…

sitespeedio.io 前端页面监控安装部署接入influxdb 到grafana

1.docker部署influxdb,部署1.8一下&#xff0c;不然语法有变化后面用不了grafana模板 docker run -d -p 8086:8086 --name influxdb -v $PWD/influxdb-data:/var/lib/influxdb influxdb:1.7.11-alpine docker exec -it influxdb_id bash #influx create user admin with pass…
最新文章