参考了hzwer学长的blog。
设P[x]表示物品带来的能量,L[x]、M[x]表示物品购买上限、单价(高级装备的L与M需要自己算)。
L[x] = min(L[x], m/M[x]) 贫穷限制了购买力。
f[i][j][k]表示在第i个物品为根的子树中,有j件x物品是用于上层的合成(那么这j件物品的能量值并不在此时体现),花费为k时带来的最大能量。
显然对于基本装备,有:
for(int i = 0; i <= L[x]; ++i) for(int j = i; j <= L[x]; ++j) f[x][i][j * M[x]] = (j - i) * P[x];
这可能是一个森林,所以对于每棵树,我们都进行dp。
在对高级装备x及其子树进行dp的时候,我们定义g[i][j]表示,对于x的前i个儿子(按邻接表的顺序定义的),花费为j,所能获得的最大能量。
假设我们要合成l个x物品,剩下的钱买一些x子树内的装备,并不用于合成。
g[tot][j] = max{g[tot - 1][j - k] + f[e[i].to][l*e[i].val][k]}
//e[i].to是x的第i个儿子,e[i].val是合成x所需的第i个子装备的数量。k表示从j中拿出k的钱买子树内装备,此时的tot还在逐渐累加,并不是一个定值
最后枚举这l个x装备中,有j个用于合成,其他用于直接增加能量
f[x][j][k] = max{g[tot][k] + P[x] * (l - j)} //tot此时就表示儿子数量了
dp完x这棵树之后,我们回到主程序。
h[i][j]表示森林中的前i棵树,花费j元得到的最大能量值。
那么h[i][j] = max{h[i - 1][j1] + f[x][0][j - j1]}
//把j给前i-1棵树与x这棵树分。因为x没有父节点了,所以没有x物品用于上层合成
#include <cstdio> #include <cstring> #include <algorithm> #define inf 1000000000 using namespace std; int n, m, P[55], M[55], L[55], tot = 0, ans; int f[55][105][2005], g[55][2005], h[55][2005]; struct adj {int to, val, next;}e[20005]; int head[55], deg[55], cnt = 1; inline int read() { int x = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar();} return x; } inline void ins(int u, int v, int w) {e[++cnt].to = v; e[cnt].val = w; e[cnt].next = head[u]; head[u] = cnt; ++deg[v];} inline void dp(int x) { if(!head[x]) { L[x] = min(L[x], m/M[x]); for(int i = 0; i <= L[x]; ++i) for(int j = i; j <= L[x]; ++j) f[x][i][j * M[x]] = (j - i) * P[x]; return ; } L[x] = inf; for(int i = head[x]; i; i = e[i].next) { dp(e[i].to); L[x] = min(L[x], L[e[i].to]/e[i].val); M[x]+= e[i].val * M[e[i].to]; } L[x] = min(L[x], m/M[x]); memset(g, -0x3f3f3f3f, sizeof(g)); g[0][0] = 0; for(int l = L[x]; l >= 0; --l) { int tot = 0; for(int i = head[x]; i; i = e[i].next) { ++tot; for(int j = 0; j <= m; ++j) for(int k = 0; k <= j; ++k) g[tot][j] = max(g[tot][j], g[tot - 1][j - k] + f[e[i].to][l * e[i].val][k]); } for(int j = 0; j <= l; ++j) for(int k = 0; k <= m; ++k) f[x][j][k] = max(f[x][j][k], g[tot][k] + P[x] * (l - j)); } } int main() { n = read(); m = read(); for(int i = 1; i <= n; ++i) { P[i] = read(); char ch[10]; scanf("%s", ch); if(ch[0] == 'A') { int x = read(); while(x--) { int v = read(), num = read(); ins(i, v, num); } }else M[i] = read(), L[i] = read(); } memset(f, -0x3f3f3f3f, sizeof(f)); for(int x = 1; x <= n; ++x) if(!deg[x]) { dp(x); ++tot; for(int i = 0; i <= m; ++i) for(int j = 0; j <= i; ++j) h[tot][i] = max(h[tot][i], h[tot - 1][j] + f[x][0][i - j]); } for(int i = 0; i <= m; ++i) ans = max(ans, h[tot][i]); printf("%d", ans); return 0; }