程序设计天梯赛L3-23 (编程题也求偏导数是吧)

题目
题意: 给定一个有向无环图,有+、-、、lnx、e的x、sinx六种操作。有若干个自变量。求到达终点的函数值以及每个变量对应的偏导数值。题目保证仅有一个终点。
思路: 用一个数组存下每个编号为i的结点的信息,操作类型和左右结点。求函数值好求的,可以topsort,也可以递归。但是求偏导数我就不会咧,递归求确实好求。拿一个map<int,map<int,map<int,double> > >维护。因为要记忆化减少重复计算,否则T一个点。
cur: 当前求哪个结点的值
wh: 0表示不求导,1表示求导
p: 对哪个自变量求导
时间复杂度: O(能过),单个自变量最多2n
log(2n),但是多个自变量就不好说了,但是有很多包含函数值的部分不会重复计算。反正能过.
代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 5e4+10;
typedef long long ll;
typedef pair<int,int> PII;
#define mem(a,x) memset(a,x,sizeof(a))
#define fir(i,a,b) for(int i=a;i<=b;++i)
struct node{
	int op; //操作
	int l,r; //左右操作数
    bool flag; //是否有出边
    double val; //值
}a[N];
int n,m,k,T;
map<int,map<int,map<int,double> > >f; //结点、是否求导、对谁求导.0:不求导、1:求导
double dfs(int cur,int wh,int p) //0:不求导,1:求导
{
	auto &tmp = f[cur][wh][p];
    if(tmp) return tmp;
    int op = a[cur].op;
    int l = a[cur].l;
    int r = a[cur].r;
    if(wh == 0) //不求导
    {
    	if(op==0) return tmp = a[cur].val;
    	if(op==1) return tmp = dfs(l,wh,p) + dfs(r,wh,p);
    	if(op==2) return tmp = dfs(l,wh,p) - dfs(r,wh,p);
    	if(op==3) return tmp = dfs(l,wh,p) * dfs(r,wh,p);
    	if(op==4) return tmp = exp(dfs(l,wh,p));
    	if(op==5) return tmp = log(dfs(l,wh,p));
    	if(op==6) return tmp = sin(dfs(l,wh,p));
    }
    else
    {
    	if(op==0) if(cur == p) return 1;else return 0;
    	if(op==1) return tmp = dfs(l,wh,p) + dfs(r,wh,p);
    	if(op==2) return tmp = dfs(l,wh,p) - dfs(r,wh,p);
    	if(op==3) return tmp = dfs(l,wh,p)*dfs(r,wh^1,p) + dfs(l,wh^1,p)*dfs(r,wh,p);
    	if(op==4) return tmp = dfs(l,wh,p)*exp(dfs(l,wh^1,p));
    	if(op==5) return tmp = (1.0/dfs(l,wh^1,p))*dfs(l,wh,p);
    	if(op==6) return tmp = cos(dfs(l,wh^1,p))*dfs(l,wh,p);
    }
}
void solve()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=0;i<n;++i)
	{
		int op; cin>>op;
		if(op==0)
		{
			double x; cin>>x;
			a[i].val = x;
		}
		else if(op<=3)
		{
			int l,r; cin>>l>>r;
			a[i].l = l,a[i].r = r;
			a[l].flag = a[r].flag = 1;
		}
		else
		{
			int l; cin>>l;
			a[i].l = l;
			a[l].flag = 1;
		}
		a[i].op = op;
	}
	int root;
	for(int i=0;i<n;++i) if(!a[i].flag) root = i;
	double res = dfs(root,0,-1);
	printf("%.3lf\n",res);
	bool flag = 1;
	for(int i=0;i<n;++i)
	{
		if(a[i].op==0)
		{
			if(!flag) printf(" ");
			printf("%.3lf",dfs(root,1,i));
			flag = false; 
		}
	}
}
signed main(void)
{
	solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值