• BZOJ1017 [JSOI2008]魔兽地图DotR 【树形dp + 背包dp】


    题目链接

    BZOJ1017

    题解

    orz hzwer

    树形dp神题

    (f[i][j][k])表示(i)号物品恰好花费(k)金币,并将(j)个物品贡献给父亲的合成时的最大收益

    计算(f[i][j][k])时,我们先枚举合成了x个(i)号物品,计算出此时的花费各种金币下最大收益
    然后就可以枚举(j le x)(k),更新(f[i][j][k])
    计算最大收益,就把第(l)个子树的(f[s][w * x][v])看做第(l)个物品的第(v)种物品【(w * x)是该子树需要提供的的贡献】
    做分组背包即可计算出花费各种金币时可得到的最大收益

    由于整体的关系不确定,我们将每棵树根拿出来再做一次分组背包即可

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = H[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define cls(s) memset(s,0,sizeof(s))
    using namespace std;
    const int maxn = 55,maxm = 2005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int H[maxn],ne = 1;
    struct EDGE{int to,nxt,w;}ed[maxm];
    inline void build(int u,int v,int w){
    	ed[ne] = (EDGE){v,H[u],w}; H[u] = ne++;
    }
    int n,m,rt,f[maxn][101][maxm],g[maxn][maxm],h[maxn][maxm];
    int W[maxn],P[maxn],M[maxn],typ[maxn],fa[maxn];
    void dfs(int u){
    	if (!typ[u]){
    		M[u] = min(M[u],m / P[u]);
    		for (int i = 0; i <= M[u]; i++)
    			for (int j = 0; j <= i; j++)
    				f[u][j][i * P[u]] = (i - j) * W[u];
    		return;
    	}
    	M[u] = INF;
    	Redge(u){
    		dfs(to = ed[k].to);
    		M[u] = min(M[u],M[to] / ed[k].w);
    		P[u] += P[to] * ed[k].w;
    	}
    	M[u] = min(M[u],m / P[u]);
    	memset(g,-0x3f3f3f3f,sizeof(g));
    	g[0][0] = 0;
    	for (int x = M[u]; x >= 0; x--){
    		int tot = 0;
    		Redge(u){
    			++tot; to = ed[k].to;
    			for (int j = 0; j <= m; j++)
    				for (int v = 0; v <= j; v++)
    					g[tot][j] = max(g[tot][j],g[tot - 1][j - v] + f[to][ed[k].w * x][v]);
    		}
    		for (int j = 0; j <= x; j++)
    			for (int v = 0; v <= m; v++){
    				if (v) g[tot][v] = max(g[tot][v],g[tot][v - 1]);
    				f[u][j][v] = max(f[u][j][v],g[tot][v] + W[u] * (x - j));
    			}
    	}
    }
    int main(){
    	memset(f,-0x3f3f3f3f,sizeof(f));
    	n = read(); m = read(); char c;
    	REP(i,n){
    		W[i] = read();
    		c = getchar(); while (c != 'A' && c != 'B') c = getchar();
    		if (c == 'A'){
    			typ[i] = 1;
    			int x = read(),to,w;
    			while (x--){
    				to = read(); w = read();
    				build(i,to,w);
    				fa[to] = i;
    			}
    		}
    		else P[i] = read(),M[i] = read();
    	}
    	int tot = 0;
    	for (int u = 1; u <= n; u++)
    		if (!fa[u]){
    			dfs(u); ++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][i - j] + f[u][0][j]);
    		}
    	int ans = 0;
    	for (int i = 0; i <= m; i++) ans = max(ans,h[tot][i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    写一个通用的事件侦听器函数
    基于LuckySheet在线表格的Excel下载功能开发
    node项目中npm 第三方包引用规则
    js 本地保存 json/txt 文件
    letcood 算法题 -- 两数相加
    ES6新增语法总结
    关于Promise,你必须知道的几点。
    Promise 基础
    学习网页收藏
    android Listview每一个item添加点击事件
  • 原文地址:https://www.cnblogs.com/Mychael/p/9014107.html
Copyright © 2020-2023  润新知