BZOJ 1065: [NOI2008]奥运物流

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


你可能感兴趣的:(BZOJ 1065: [NOI2008]奥运物流)