bzoj1017

参考了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;
}

猜你喜欢

转载自blog.csdn.net/richard_for_oi/article/details/79834637