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 }