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