1065: [NOI2008]奥运物流 - BZOJ

1065: [NOI2008]奥运物流 - BZOJ_第1张图片

1065: [NOI2008]奥运物流 - BZOJ_第2张图片

Sample Input
4 1 0.5
2 3 1 3
10.0 10.0 10.0 10.0
Sample Output
30.00

 

推荐题解:http://blog.csdn.net/whjpji/article/details/7593329

这个题解比较详细,代码上还有注释,比较容易懂

附上徐源盛-对一类动态规划问题的研究

里面有题目讲解

首先我们先算出R(1)的公式,就是(d为深度,根的深度为0,len为环的长度)

1065: [NOI2008]奥运物流 - BZOJ_第3张图片

这个怎么算呢

首先如果这个是树的话,我们就知道

R(1)等于这个式子的上面那一部分,但是1还有后继,所以有一个环

我们把1拆成两个点,一个做根,一个做叶子

于是R(1)=

       n

sssssssssss

   i

      g          ci*k^di          +       R(1)*k^len

   m

aaaaaaaaaaa

       i=2

 

然后我们可以证明如果修改后继,一定是修改为1(因为修改为1,可以最大限度的减小深度和环的长度,这个比较一下就行了)

然后是树形dp,因为有环所以我们先去环,就是枚举环的长度,把那个断点的后继设为1,这样就把分母固定了,我们要做的就是让分子越大越好

dp[i][j][d]表示以i为根的子树,修改j次,i与根的距离为d的最大贡献


1065: [NOI2008]奥运物流 - BZOJ_第4张图片

上面就是i不修改后继的,下面就是i修改后继的

然后用01背包解决转移(注意,修改的话,c>0才行)

  1 const
  2         maxn=62;
  3 var
  4         f,g:array[0..maxn,0..maxn,0..maxn]of double;
  5         c,ff,kk:array[0..maxn]of double;
  6         pre:array[0..maxn]of longint;
  7         ans:double;
  8         n,m:longint;
  9  
 10 procedure init;
 11 var
 12         i:longint;
 13 begin
 14         read(n,m,kk[1]);
 15         for i:=2 to n do
 16           kk[i]:=kk[i-1]*kk[1];
 17         for i:=1 to n do
 18           read(pre[i]);
 19         for i:=1 to n do
 20           read(c[i]);
 21 end;
 22  
 23 function min(x,y:double):double;
 24 begin
 25         if x<y then exit(x);
 26         exit(y);
 27 end;
 28  
 29 function max(x,y:double):double;
 30 begin
 31         if x>y then exit(x);
 32         exit(y);
 33 end;
 34  
 35 function min(x,y:longint):longint;
 36 begin
 37         if x<y then exit(x);
 38         exit(y);
 39 end;
 40  
 41 procedure dp(u,d:longint);
 42 var
 43         i,j,k,dd:longint;
 44 begin
 45         for i:=2 to n do
 46           if pre[i]=u then dp(i,d+1);
 47         for dd:=min(2,d) to d do
 48           begin
 49             fillchar(ff,sizeof(ff),0);
 50             for i:=2 to n do
 51               if pre[i]=u then
 52               for j:=m downto 0 do
 53                 for k:=j downto 0 do
 54                   ff[j]:=max(ff[j],ff[k]+g[i,j-k,dd]);
 55             for j:=0 to m do
 56               f[u,j,dd]:=ff[j]+c[u]*kk[dd];
 57           end;
 58         if d>1 then
 59         begin
 60           fillchar(ff,sizeof(ff),0);
 61           for i:=2 to n do
 62             if pre[i]=u then
 63             for j:=m downto 0 do
 64               for k:=j downto 0 do
 65                 ff[j]:=max(ff[j],ff[k]+g[i,j-k,1]);
 66           for j:=1 to m do
 67             f[u,j,1]:=ff[j-1]+c[u]*kk[1];
 68         end;
 69         for j:=0 to m do
 70           for dd:=0 to d-1 do
 71             g[u,j,dd]:=max(f[u,j,dd+1],f[u,j,1]);
 72 end;
 73  
 74 procedure work;
 75 var
 76         i,j,k,l,len,tmp:longint;
 77         now:double;
 78 begin
 79         i:=pre[1];
 80         len:=2;
 81         while i<>1 do
 82           begin
 83             fillchar(f,sizeof(f),0);
 84             fillchar(g,sizeof(g),0);
 85             tmp:=pre[i];
 86             pre[i]:=1;
 87             now:=0;
 88             for j:=2 to n do
 89               if pre[j]=1 then dp(j,1);
 90             fillchar(ff,sizeof(ff),0);
 91             for j:=2 to n do
 92               if pre[j]=1 then
 93               for k:=m downto 0 do
 94                 for l:=k downto 0 do
 95                   ff[k]:=max(ff[k],ff[l]+f[j,k-l,1]);
 96             for j:=0 to m-1 do
 97               now:=max(now,ff[j]);
 98             if tmp=1 then now:=max(now,ff[m]);
 99             ans:=max(ans,(now+c[1])/(1-kk[len]));
100             pre[i]:=tmp;
101             i:=pre[i];
102             inc(len);
103           end;
104         writeln(ans:0:2);
105 end;
106  
107 begin
108         init;
109         work;
110 end.
View Code

 

 

 

 

你可能感兴趣的:(2008)