基环内向树上DP。
09年-《对一类动态规划问题的研究》
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=60+5;
double f[N][N][N],g[N][N][N],FF[N],C[N],K[N];
int n,pre[N],m;
void dp(int u,int d){
for(int v=2;v<=n;v++)if(pre[v]==u)dp(v,d+1);
for(int i=min(d,2);i<=d;i++){
memset(FF,0,sizeof(FF));
for(int v=2;v<=n;v++)
if(pre[v]==u)
for(int j=m;j>=0;j--)
for(int k=j;k>=0;k--)
FF[j]=max(FF[j],FF[k]+g[v][j-k][i]);
for(int j=0;j<=m;j++)
f[u][j][i]=FF[j]+C[u]*K[i];
}
if(d>1){
memset(FF,0,sizeof(FF));
for(int v=2;v<=n;v++)
if(pre[v]==u)
for(int j=m;j>=0;j--)
for(int k=j;k>=0;k--)
FF[j]=max(FF[j],FF[k]+g[v][j-k][1]);
for(int j=1;j<=m;j++)
f[u][j][1]=FF[j-1]+C[u]*K[1];
}
for(int i=0;i<=m;i++)
for(int j=0;j<d;j++)
g[u][i][j]=max(f[u][i][j+1],f[u][i][1]);
}
int main(){
//freopen("a.in","r",stdin);
scanf("%d%d%lf",&n,&m,K+1);
for(int i=2;i<=n;i++)K[i]=K[i-1]*K[1];
for(int i=1;i<=n;i++)scanf("%d",pre+i);
for(int i=1;i<=n;i++)scanf("%lf",C+i);
double ans=0;
for(int now=pre[1],len=2;now!=1;now=pre[now],len++){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
int recoder=pre[now];pre[now]=1;
for(int i=2;i<=n;i++)if(pre[i]==1)dp(i,1);
memset(FF,0,sizeof(FF));
for(int u=2;u<=n;u++)
if(pre[u]==1)
for(int j=m;j>=0;j--)
for(int k=j;k>=0;k--)
FF[j]=max(FF[j],FF[k]+f[u][j-k][1]);
double nowans=0;
for(int i=0;i<m;i++)nowans=max(nowans,FF[i]);
if(recoder==1)nowans=max(nowans,FF[m]);
ans=max(ans,(nowans+C[1])/(1-K[len]));
pre[now]=recoder;
}
printf("%.2lf\n",ans);
return 0;
}