基环内向树上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; }