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
",ans);
66 }
原文地址:https://www.cnblogs.com/qzqzgfy/p/5594596.html