zoukankan      html  css  js  c++  java
  • 树上背包

    参考


    [CTSC1997]选课

    首先是原题的题解:

    显然先修结构是森林, 设一个超级根, 作为所有没有先修课节点的先修课, 价值为 0, 然后在这颗超级树里选 m+1 个答案, 就是原题的答案。

    设 fu,i 表示在以 u 为根的子树里选 i 门课的最大得分, 那么:

    [sf f_{u,i} = max_{vin som(u),sum k_v = i-1} {sum f_{v,k_v}} + a_u ]

    这个可以通过背包合并子树, 然后移位即可。

    合并子树 u,v:

    [sf f_{u,i} = max_k{f_{u,i-k}+f_{v,k}} ]

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 303;
    
    int n, m, a[N];
    vector<int> e[N];
    
    int f[N][N];
    
    void dfs(int u) {
    	for(vector<int>::iterator it = e[u].begin(); it != e[u].end(); ++it) {
    		int v = *it;
    		dfs(v);
    		for(int j = m; j >= 1; --j)
    			for(int k = 0; k <= j; ++k)
    				f[u][j] = max(f[u][j], f[u][k] + f[v][j-k]);
    	}
    	for(int i = m+1; i >= 1; --i) f[u][i] = f[u][i-1] + a[u];
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n; ++i) {
    		int p;
    		scanf("%d%d", &p, &a[i]);
    		e[p ? p : n+1].push_back(i);
    	}
    	dfs(n+1);
    	cout << f[n+1][m+1];
    	return 0;
    }
    

    上下界优化:

    void dfs(int u) {
    	siz[u] = 1;
    	for(vector<int>::iterator it = e[u].begin(); it != e[u].end(); ++it) {
    		int v = *it;
    		dfs(v);
    		for(int j = min(m, siz[u]+siz[v]); j >= 1; --j)
    			for(int k = max(0,j-siz[u]); k <= j && k <= siz[v]; ++k)
    				f[u][j] = max(f[u][j], f[u][j-k] + f[v][k]);
    		siz[u] += siz[v];
    	}
    	for(int i = m+1; i >= 1; --i) f[u][i] = f[u][i-1] + a[u];
    }
    

    优化后的总复杂度是 O(n2) 的。

  • 相关阅读:
    博弈入门
    悼念512汶川大地震遇难同胞——老人是真饿了 hdu 2187
    数塔 简单的 动态规划
    ~~~~~~~~~~~析构函数~~~~~~~~
    构造函数的重载
    利用 构造函数 实现数据成员的 初始化
    类和对象
    函数 的 重载 和 函数 模版
    nexus Maven私服的相关配置
    docker-compose bug
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14414735.html
Copyright © 2011-2022 走看看