HDU 5534 Partial Tree 完全背包
2015-11-02 01:00
344 查看
题意:
让你构造一个有\(n(2 \leq n \leq 2015)\)个节点的树。然后定义这棵树的\(coolness\)为\(\sum{f(d)}\),其中\(d\)是每个节点的度数,函数\(f\)在输入中给出。
分析:
一颗含有\(n\)个节点的树,有\(n-1\)条边,度数之和为\(2n-2\)。所以我们可以转化成一个完全背包问题:
背包的容量为\(2n-2\),我们要恰好选\(n\)个物品而且要恰好装满背包。体积为\(i\)的物品的价值为\(f(i)\),而且每种物品有无穷多个。
所以可以设计出类似的状态:\(d(i, j)\)表示选了\(i\)件物品,体积为\(j\)时所能得到的最大价值。
最后发现总的时间复杂度是\(O(n^3)\)的。
分析原因:问题就在于转移的过程会有很多相同的状态。比如背包里的物品为\((1, 2, 3)\),这个状态可以由\((1, 2)\)后面加个\(3\)得到,也可以由\((1, 3)\)后面加个\(2\)得到。事实上具体是由什么顺序转移过来我们是不关心的,我们只关系每种物品选了多少件。
参考叉姐的思路:
一开始假设大家的度数都为\(1\),然后慢慢地增大,让大家的度数和增大到\(2n-2\)。
设计新的状态\(d(i, j)\)表示已经考虑过增大到\(\leq i\)的度数,总度数和为\(j\),能得到的最大价值。
那么有状态转移方程:$d(i,j)=max \{ (d(i-1,j),d(i,j-(i-1))+f(i)-f(1)) \} $
最终所求的答案就是\(d(n-1,n-2)\)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 2050; int n; int f[maxn]; //滚动数组优化一下空间 int d[2][maxn]; int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i = 1; i < n; i++) scanf("%d", f + i); memset(d, 0, sizeof(d)); int cur = 1; d[1][0] = n * f[1]; for(int i = 2; i <= n - 1; i++) { cur ^= 1; memset(d[cur], 0, sizeof(d[cur])); for(int j = 0; j < i - 1; j++) d[cur][j] = d[cur^1][j]; for(int j = i - 1; j <= n - 2; j++) d[cur][j] = max(d[cur^1][j], d[cur][j-i+1] + f[i] - f[1]); } printf("%d\n", d[cur][n - 2]); } return 0; }
相关文章推荐
- 12、Swift语言中类和结构体的应用
- bash学习
- 2015/11/1
- mysql 自增主键重排
- [HDU 2255]奔小康赚大钱[KM算法]
- [c]C语言小练习题
- AndroidListView工作理完全解析 带你从源码的角度彻底理解
- AndroidListView工作理完全解析 带你从源码的角度彻底理解
- 近两天项目冲刺
- Android动画
- 对话(Dialog)
- React.js学习笔记(一):组件协同与mixin
- android添加触摸事件
- 【安卓开发问题解决】怎样打开手机的logcat开关
- 20135223何伟钦—信息安全系统设计基础期中总结
- Seventh scrum meeting - 2015/11/1
- 周期
- Almost Sorted Array
- 判断1000年---2000年之间的闰年
- poj 1579(记忆化搜索)