BZOJ 1065 奥运物流
http://www.lydsy.com/JudgeOnline/problem.php?id=1065
思路:由于n个点,有n条边,因此由根就会引出一个环,我们枚举环的长度,在那个长度断开,我们假设len为环的长度。
由于R(i)满足
而产生环时,R[1]=Σci*k^di + R[1]*(k^len),得到
R[1]=(Σci*k^di)/(1-k^len)
因此我们枚举len,然后做树形DP,f[i][j][k]代表第i个点,修改了j次,当前深度为k
那么最后的贡献是Σf[i][j][1],i为1的直接儿子,用一个01背包统计,最后答案就是(ans+c[1])/(1-k^len)
有个蛋疼的地方就是做01背包的时候。。要注意循环变量的顺序,不要重复统计。。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int n,m,pre[200005]; 7 double K[200005],c[200005],f[80][80][80],g[80][80][80],F[200005]; 8 int read(){ 9 int t=0,f=1;char ch=getchar(); 10 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 11 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 12 return t*f; 13 } 14 void dp(int x,int dep){ 15 for (int i=2;i<=n;i++) if (pre[i]==x) dp(i,dep+1); 16 for (int d=std::min(2,dep);d<=dep;d++){ 17 for (int j=0;j<=m;j++) F[j]=0; 18 for (int i=2;i<=n;i++) 19 if (pre[i]==x) 20 for (int j=m;j>=0;j--) 21 for (int k=j;k>=0;k--) 22 F[j]=std::max(F[j],F[k]+g[i][j-k][d]); 23 for (int i=0;i<=m;i++) 24 f[x][i][d]=F[i]+c[x]*K[d]; 25 } 26 if (dep>1){ 27 for (int i=0;i<=m;i++) F[i]=0; 28 for (int i=2;i<=n;i++) 29 if (pre[i]==x) 30 for (int j=m;j>=0;j--) 31 for (int k=j;k>=0;k--) 32 F[j]=std::max(F[j],F[k]+g[i][j-k][1]); 33 for (int i=1;i<=m;i++) 34 f[x][i][1]=F[i-1]+c[x]*K[1]; 35 } 36 for (int j=0;j<=m;j++) 37 for (int d=0;d<dep;d++) 38 g[x][j][d]=std::max(f[x][j][d+1],f[x][j][1]); 39 } 40 int main(){ 41 n=read();m=read();scanf("%lf",&K[1]); 42 for (int i=2;i<=n;i++) K[i]=K[i-1]*K[1]; 43 for (int i=1;i<=n;i++) pre[i]=read(); 44 for (int i=1;i<=n;i++) scanf("%lf",&c[i]); 45 double ans=0; 46 for (int I=pre[1],len=2;I-1;I=pre[I],len++){ 47 for (int i=1;i<=n;i++) 48 for (int j=0;j<=m;j++) 49 for (int k=0;k<=n;k++) 50 f[i][j][k]=g[i][j][k]=0; 51 int tmp=pre[I];pre[I]=1; 52 for (int i=2;i<=n;i++) if (pre[i]==1) dp(i,1); 53 for (int i=0;i<=m;i++) F[i]=0; 54 for (int i=2;i<=n;i++) 55 if (pre[i]==1) 56 for (int j=m;j>=0;j--) 57 for (int k=j;k>=0;k--) 58 F[j]=std::max(F[j],F[k]+f[i][j-k][1]); 59 double now=0; 60 for (int i=0;i<m;i++) now=std::max(now,F[i]); 61 if (tmp==1) now=std::max(now,F[m]); 62 pre[I]=tmp; 63 ans=std::max(ans,(now+c[1])/(1-K[len])); 64 } 65 printf("%.2lf\n",ans); 66 }