bzoj 1017 tree dp

 

这道题几经波折啊。

 

最开始和vfleaking一样,把题意理解错了,认为一个装备可能被多个装备依赖,然后想不出来,去看题解。

发现自己理解错了题意,自己想想,其实也不难想到dp[i][j][k]表示“i号节点代表的子树,用掉j的钱,给父亲预留k个自己(但还是父亲付钱)”的状态,写出来交上去就是T,

开始以为是常数问题,优化半天还是T,看了他人AC代码,才发现自己算法有一定问题:重复计算了很多东西。

树形动规,一般在大的树规下,每个节点还会对儿子们来一次”资源分配“,一般是用背包解决,这道题也是这样,但又有一点不一样,就是我们也要给该子树的根节点本身分配资源,

我就是这儿重复计算了,对于所有儿子的同一k,我算了多次。

 

  1 /**************************************************************
  2     Problem: 1017
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:16524 ms
  7     Memory:48316 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <vector>
 13 #define max(a,b) ((a)>(b)?(a):(b))
 14 #define min(a,b) ((a)<(b)?(a):(b))
 15 #define maxn 55 
 16 #define maxm 2010
 17 #define maxl 110
 18 #define oo 0x3f3f3f3f
 19 using namespace std;
 20  
 21  
 22 int n, m;
 23 int indgr[maxn];
 24 int power[maxn], cost[maxn], limit[maxn];
 25 int head[maxn], next[maxn], dest[maxn], wght[maxn], tot;
 26  
 27 int dp[maxn][maxm][maxl];
 28 int ep[maxm];
 29  
 30 void insert( int a, int b, int w ) {
 31     tot++;
 32     wght[tot] = w;
 33     dest[tot] = b;
 34     next[tot] = head[a];
 35     head[a] = tot;
 36 }
 37 void dfs( int i ) {
 38     if( !head[i] ) return;
 39     cost[i] = 0;
 40     limit[i] = oo;
 41  
 42     for( int t=head[i]; t; t=next[t] ) {
 43         int s = dest[t], w = wght[t];
 44         dfs( s );
 45         cost[i] += cost[s]*w;
 46         limit[i] = min( limit[i], limit[s]/w );
 47     }
 48 }
 49  
 50  
 51 void dodp( int i ) {
 52     if( !head[i] ) {
 53         for( int l=0; l<=limit[i]; l++ )
 54             for( int k=l; k>=0; k-- ) {
 55                 int self = (l-k);
 56                 int j = self*cost[i];
 57                 if( j>m ) break;
 58                 dp[i][j][k] = self*power[i];
 59             }
 60         return;
 61     }
 62     for( int t=head[i]; t; t=next[t] )
 63         dodp( dest[t] );
 64     for( int l=0; l<=limit[i]; l++ ) {
 65         for( int j=0; j<=m; j++ ) ep[j]=0;
 66         for( int t=head[i]; t; t=next[t] ) {
 67             int v = dest[t], w = wght[t];
 68             int vl = l*w;
 69             for( int j=m; j>=0; j-- )
 70                 for( int jj=0; jj<=j; jj++ )
 71                     ep[j] = max( ep[j], ep[j-jj]+dp[v][jj][vl] );
 72         }
 73         for( int j=0; j<=m; j++ )
 74             for( int k=l; k>=0; k-- ) {
 75                 int self = l-k;
 76                 int remain =  j- self*cost[i];
 77                 if( remain<0 ) break;
 78                 dp[i][j][k] = max( dp[i][j][k], ep[remain]+self*power[i] );
 79             }
 80     }
 81 }
 82  
 83 int main() {
 84     scanf( "%d%d", &n, &m );
 85     for( int i=1; i<=n; i++ ) {
 86         char type[10];
 87         scanf( "%d%s", power+i, type );
 88         if( type[0]=='A' ) {
 89             int cnt;
 90             scanf( "%d", &cnt );
 91             for( int t=1,c,w; t<=cnt; t++ ) {
 92                 scanf( "%d%d", &c, &w );
 93                 insert( i, c, w );
 94                 indgr[c]++;
 95             }
 96         } else
 97             scanf( "%d%d", cost+i, limit+i );
 98     }
 99     int root = 0;
100     for( int i=1; i<=n; i++ ) 
101         if( indgr[i]==0 ) {
102             root = i;
103             break;
104         }
105     memset( dp, 129, sizeof(dp) );
106     dfs(root);
107     dodp(root);
108     int ans = 0;
109     for( int j=0; j<=m; j++ ) ans = max( ans, dp[root][j][0] );
110     printf( "%d\n", ans );
111 }
View Code

 

posted @ 2015-02-21 15:50  idy002  阅读(160)  评论(0编辑  收藏  举报