4202. Shopping

来源:互联网 发布:声音放大器偷听软件 编辑:程序博客网 时间:2024/05/18 10:57

题目大意

给定一棵n个结点的数,每个点有参数(w,c,d)表示价值为w,代价为c,有d个物品。初始有m元钱。
现在要选出一个连通块使得价值最大。

Data Constraint
n500

题解

考虑点剖,每次选择重心就进行多重背包DP。
如果不选择就递归进子树继续考虑。
每次DP的时候是一个树型依赖DP,可以在DFS序上DP,每次选择一个点i就转移到i+1,否则就转移到i+size[i]+1
注意要按二的幂将物品分组。

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std ;#define N 500 + 10#define M 4000 + 10const int inf = 0x7FFFFFFF ;struct Object {    int w , c , d ;} P[N] ;bool vis[N] ;int Node[2*N] , Next[2*N] , Head[N] , tot ;int W[20*N] , V[20*N] , st[N] , ed[N] ;int DFN[N] , S[N] , R[N] , Size[N] , Maxs[N] ;int f[N][M] , g[M] ;int T , n , m , q , ans ;int Root , All , Cnt , Minv ;void link( int u , int v ) {    Node[++tot] = v ;    Next[tot] = Head[u] ;    Head[u] = tot ;}void DP() {    int Num = 0 ;    for (int i = 1 ; i <= Cnt ; i ++ ) {        for (int j = 0 ; j <= m ; j ++ ) f[i][j] = -inf ;        int now = S[i] ;        if ( i == 1 ) {            if ( !P[now].d ) return ;            for (int k = 1 ; k <= P[now].d ; k ++ ) f[1][k*P[now].c] = k * P[now].w ;            continue ;        }        int x = P[now].d - 1 , k = 1 ;        st[i] = Num + 1 ;        while ( x >= k ) {            ++ Num ;            W[Num] = P[now].w * k ;            V[Num] = P[now].c * k ;            x -= k ;            k *= 2 ;        }        if ( x ) {            ++ Num ;            W[Num] = P[now].w * x ;            V[Num] = P[now].c * x ;        }        ed[i] = Num ;    }    for (int i = 2 ; i <= Cnt ; i ++ ) {        for (int j = m ; j >= 0 ; j -- ) {            if ( j >= P[S[i]].c ) g[j] = f[i-1][j-P[S[i]].c] + P[S[i]].w ;            else g[j] = -inf ;        }        for (int k = st[i] ; k <= ed[i] ; k ++ ) {            for (int j = m ; j >= V[k] ; j -- ) g[j] = max( g[j] , g[j-V[k]] + W[k] ) ;        }        for (int j = 0 ; j <= m ; j ++ ) f[i][j] = max( f[i][j] , g[j] ) ;        for (int k = 0 ; k <= m ; k ++ ) f[R[S[i]]][k] = max( f[R[S[i]]][k] , f[i-1][k] ) ;    }    for (int i = 1 ; i <= Cnt ; i ++ )        for (int j = 0 ; j <= m ; j ++ ) ans = max( ans , f[i][j] ) ;}void GetSize( int x , int F ) {    Size[x] = Maxs[x] = 1 ;    for (int p = Head[x] ; p ; p = Next[p] ) {        if ( Node[p] == F || vis[Node[p]] ) continue ;        GetSize( Node[p] , x ) ;        Size[x] += Size[Node[p]] ;        if ( Size[Node[p]] > Maxs[x] ) Maxs[x] = Size[Node[p]] ;    }}void GetRoot( int x , int F ) {    Maxs[x] = max( Maxs[x] , Size[All] - Size[x] ) ;    if ( Maxs[x] < Minv ) Minv = Maxs[x] , Root = x ;    for (int p = Head[x] ; p ; p = Next[p] ) {        if ( Node[p] == F || vis[Node[p]] ) continue ;        GetRoot( Node[p] , x ) ;    }}void DFS( int x , int F ) {    DFN[x] = R[x] = ++ Cnt ;    S[Cnt] = x ;    for (int p = Head[x] ; p ; p = Next[p] ) {        if ( Node[p] == F || vis[Node[p]] ) continue ;        DFS( Node[p] , x ) ;        R[x] = R[Node[p]] ;    }}void DIV( int x ) {    Minv = 0x7FFFFFFF ;    Root = All = x ;    GetSize( x , 0 ) ;    GetRoot( x , 0 ) ;    Cnt = 0 ;    DFS( Root , 0 ) ;    DP() ;    vis[Root] = 1 ;    for (int p = Head[Root] ; p ; p = Next[p] ) {        if ( vis[Node[p]] ) continue ;        DIV( Node[p] ) ;    }}int main() {    freopen( "shopping.in" , "r" , stdin ) ;    freopen( "shopping.out" , "w" , stdout ) ;    scanf( "%d" , &T ) ;    while ( T -- ) {        tot = ans = 0 ;        memset( vis , 0 , sizeof(vis) ) ;        memset( Head , 0 , sizeof(Head) ) ;        scanf( "%d%d" , &n , &m ) ;        for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &P[i].w ) ;        for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &P[i].c ) ;        for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &P[i].d ) ;        for (int i = 1 ; i < n ; i ++ ) {            int u , v ;            scanf( "%d%d" , &u , &v ) ;            link( u , v ) , link( v , u ) ;        }        DIV( 1 ) ;        printf( "%d\n" , ans ) ;    }    return 0 ;}

以上.

0 0
原创粉丝点击