BZOJ1065: [NOI2008]奥运物流

来源:互联网 发布:js object array 编辑:程序博客网 时间:2024/05/07 12:31

Description

  2008北京奥运会即将开幕,举国上下都在为这一盛事做好准备。为了高效率、成功地举办奥运会,对物流系统
进行规划是必不可少的。物流系统由若干物流基站组成,以 1 … N 进行编号。每个物流基站 i 都有且仅有一个
后继基站 Si,而可以有多个前驱基站。基站 i 中需要继续运输的物资都将被运往后继基站 Si,显然一个物流基
站的后继基站不能是其本身。编号为 1 的物流基站称为控制基站,从任何物流基站都可将物资运往控制基站。注
意控制基站也有后继基站,以便在需要时进行物资的流通。在物流系统中,高可靠性与低成本是主要设计目。对于
基站 i ,我们定义其“可靠性” R(i) 如下:设物流基站 i 有 w 个前驱基站 P1,P2, … Pw ,即这些基站以 i
为后继基站,则基站 i 的可靠性 R(i) 满足下式:

其中 Ci 和 k 都是常实数且恒为正,且有 k 小于 1 。整个系统的可靠性与控制基站的可靠性正相关,我们
的目标是通过修改物流系统,即更改某些基站的后继基站,使得控制基站的可靠性 R(1) 尽量大。但由于经费限制
,最多只能修改 m 个基站的后继基站,并且,控制基站的后继基站不可被修改。因而我们所面临的问题就是,如
何修改不超过 m 个基站的后继,使得控制基站的可靠性 R(1) 最大化。

Input

  输入第一行包含两个整数与一个实数,N,m,k。其中 N 表示基站数目,m 表示最多可修改的后继基站数目,
k 分别为可靠性定义中的常数。第二行包含 N 个整数,分别是 S1,S2…SN ,即每一个基站的后继基站编号。第三
行包含 N 个正实数,分别是 C1,C2…CN ,为可靠性定义中的常数

Output

  输出仅包含一个实数,为可得到的最大 R(1)。精确到小数点两位

Sample Input

4 1 0.5
2 3 1 3
10.0 10.0 10.0 10.0

Sample Output

30.00

HINT

  对于所有的数据,满足 m≤N≤60,Ci≤106,0.3≤k<1 ,请使用双精度实数,无需考虑由此带来的误差。

Source

DP
i点对1的贡献为c[i]*k^dep[i]/(1-k^len)
f[i][j][k]表示i的子树,修改j次,i这个点的深度为k
树形DP,中间背包DP即可
详见http://wenku.baidu.com/link?url=PVSE3koLW6EtYso_K6TtBkKBPQSm0XNsBBtcqn9gf9yvpEwPs6dliLSXiJ8dWmGtwK0FRUBnmXO-UdhbyyvvUOKjm0nl7SHoOFl3CpFeoo3
#include <bits/stdc++.h>using namespace std;const int MAXN = 62;const double INF = 1e20;double f[MAXN][MAXN][MAXN], g[MAXN][MAXN][MAXN], table[MAXN], p, F[MAXN], c[MAXN], ans;int n, m, fa[MAXN];vector < int > e[MAXN];inline void dp(int x, int d){for( int i = 0 ; i < e[ x ].size() ; i++ ) dp( e[ x ][ i ], d + 1 );for( int dep = min( 2, d ) ; dep <= d ; dep++ ){memset( F, 0, sizeof F );for( int i = 0 ; i < e[ x ].size() ; i++ )for( int j = m ; j >= 0 ; j-- )for( int k = j ; k >= 0 ; k-- )F[ j ] = max( F[ j ], F[ k ] + g[ e[ x ][ i ] ][ j - k ][ dep ] );for( int j = 0 ; j <= m ; j++ ) f[ x ][ j ][ dep ] = F[ j ] + c[ x ] * table[ dep ];}if( d ^ 1 ){memset( F, 0, sizeof F );for( int i = 0 ; i < e[ x ].size() ; i++ )for( int j = m ; j >= 0 ; j-- )for( int k = j ; k >= 0 ; k-- )F[ j ] = max( F[ j ], F[ k ] + g[ e[ x ][ i ] ][ j - k ][ 1 ] );for( int j = 1 ; j <= m ; j++ ) f[ x ][ j ][ 1 ] = F[ j - 1 ] + c[ x ] * p;}for( int i = 0 ; i <= m ; i++ ) for( int j = 0 ; j < d ; j++ )g[ x ][ i ][ j ] = max( f[ x ][ i ][ j + 1 ], f[ x ][ i ][ 1 ] );}int main(){scanf( "%d%d%lf", &n, &m, &p );table[ 0 ] = 1; for( int i = 1 ; i <= n ; i++ ) table[ i ] = table[ i - 1 ] * p;for( int i = 1 ; i <= n ; i++ ) scanf( "%d", &fa[ i ] );for( int i = 1 ; i <= n ; i++ ) scanf( "%lf", &c[ i ] );for( int x = fa[ 1 ], len = 2 ; x ^ 1 ; x = fa[ x ], len++ ){for( int i = 1 ; i <= n ; i++ ) e[ i ].clear();memset( f, 0, sizeof f );memset( g, 0, sizeof g );double now = 0;for( int i = 2 ; i <= n ; i++ ) if( i ^ x ) e[ fa[ i ] ].push_back( i ); else e[ 1 ].push_back( i );for( int i = 0 ; i < e[ 1 ].size() ; i++ ) dp( e[ 1 ][ i ], 1 );memset( F, 0, sizeof F );for( int i = 0 ; i < e[ 1 ].size() ; i++ )for( int j = m ; j >= 0 ; j-- )for( int k = j ; k >= 0 ; k-- )F[ j ] = max( F[ j ], F[ k ] + f[ e[ 1 ][ i ] ][ j - k ][ 1 ] );for( int j = 0 ; j < m ; j++ ) now = max( now, F[ j ] );if( fa[ x ] == 1 ) now = max( now, F[ m ] );ans = max( ans, ( now + c[ 1 ] ) / ( 1 - table[ len ] ) );}return printf( "%.2lf\n", ans ), 0;}


0 0