参考论文http://wenku.baidu.com/view/8ab3daef5ef7ba0d4a733b25.html

参考一篇写的很好的博文http://www.cnblogs.com/GXZC/archive/2013/01/13/2858649.html

题目链接http://www.luogu.org/problem/show?pid=1273

首先确定泛化物品的定义:价值随着体积变化的物体,如01背包中的f[i](体积为i时的最大价值最f[i])。

泛化物品+普通物品:

还是01背包,我们是怎么在泛化物品f[i]中加入一个体积为v,价值为w的普通物品的?

f[i]=max(f[i],f[i-v]+w);

O(n)解决。

分析题目:可以看作是叶子节点的v=1,非叶子节点的v=0,w=父亲到该点的费用*(-1)+该点的money。就是一个树形依赖模型,每个节点是一个物品。

设f[i][j]表示dfs序小于等于节点i的所有节点(物品)中,体积为j时的最大价值。

设s为i的一个孩子。

则f[i]管理的范围为红色圈,f[s]管理的范围为蓝色圈。

从上往下(父亲-->孩子)dfs时,先让f[s]=f[i](s继承i的全部信息)

强制让f[s]必须选择s,然后往下对s进行dp。

让f[s]必须选普通物品s是因为选择了s才能选s的孩子:f[s]=f[i]; f[s][j]=max(f[s][j],f[s][j-v]+w);就是说,f[s]=f[i]+物品s

如果不是选择孩子之前必须选择父亲:f[s]=max(f[i],f[i]+物品s)

回溯(孩子-->父亲)时:将f[s]与f[i]合并。

泛化物品的并: 因为两个泛化物品之间存在交集,所以不能同时两者都取,那么我们就需要求 泛化物品的并,对同一体积,我们需要选取两者中价值较大的一者,效率 O(C)。

F[j] = max{ F1[j] , F2[j] } (C>=j>=0)

我的代码以及注释:

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; const int N=,Inf=(int)1e9;
struct node{
int x,y,d,next;
}a[*N];
int len,n,m;
int first[N],v[N],w[N],f[N][N],cost[N]; int maxx(int x,int y){return x>y ? x:y;} void ins(int x,int y,int d)
{
len++;
a[len].x=x;a[len].y=y;a[len].d=d;
a[len].next=first[x];first[x]=len;
} void init()
{
len=;
memset(first,,sizeof(first));
for(int i=;i<=n-m;i++)
{
int k,x,d;
scanf("%d",&k);
for(int j=;j<=k;j++)
{
scanf("%d%d",&x,&d);
ins(i,x,d);ins(x,i,d);
}
}
for(int i=n-m+;i<=n;i++) scanf("%d",&w[i]);
for(int i=;i<=n-m;i++) v[i]=;
for(int i=n-m+;i<=n;i++) v[i]=;
} void dfs(int x,int fa)
{
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y!=fa)
{
if(y>=n-m+) cost[y]=-a[i].d+w[y];
else cost[y]=-a[i].d;
dfs(y,x);
}
}
} void dp(int x,int fa)
{
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y,V=v[y],W=cost[y];
if(y==fa) continue; for(int j=;j<=n;j++) f[y][j]=f[x][j];
dp(y,x); // 泛化物品(f[x])加普通物品(节点y:V=v[y],W=cost[y])
// 初始化f[y]:f[y][j]=max(f[y][j],f[y][j-V]+W); // 泛化物品(f[x])与泛化物品(f[y])合并(f[x]与f[y]存在交集)
// f[x][j]=maxx(f[x][j],f[y][j+V]);
for(int j=V;j<=n-V;j++)
f[x][j]=maxx(f[x][j],f[y][j-V]+W);//加普通物品y应放在dp(y)后,因为f[y]是表示y可选可不选的,如果先压进去就必须选。
}
} int main()
{
freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
scanf("%d%d",&n,&m);
init();
dfs(,);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
if(j==) f[i][j]=;
else f[i][j]=-Inf;
dp(,);
int ans=;
for(int i=n;i>=;i--)
if(f[][i]>=) {printf("%d\n",i);return ;}
printf("0\n");
return ;
}

【LuoguP1273有线电视网】树形依赖背包的更多相关文章

  1. luoguP1273 有线电视网 [树形dp]

    题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从转播站到转播站以及从 ...

  2. Luogu P1273 有线电视网(树形dp+背包)

    P1273 有线电视网 题面 题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部 ...

  3. BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)

    BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...

  4. BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)

    BZOJ 洛谷 \(shadowice\)已经把他的思路说的很清楚了,可以先看一下会更好理解? 这篇主要是对\(Claris\)题解的简单说明.与\(shadowice\)的做法还是有差异的(比如并没 ...

  5. bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)

    菜菜推荐的“水题”虐了我一天T T...(菜菜好强强qwq~ 显然是个分数规划题,二分答案算出p[i]-mid*s[i]之后在树上跑依赖背包,选k个最大值如果>0说明还有更优解. 第一次接触树形 ...

  6. Gym - 100502G Outing (强连通缩点+树形依赖背包)

    题目链接 问题:有n个人,最多选k个,如果选了某个人就必须选他指定的另一个人,问最多能选多少个人. 将每个人所指定的人向他连一条单向边,则每一个点都有唯一的前驱,形成的图是个基环树森林,在同一个强连通 ...

  7. RNQOJ [stupid]愚蠢的矿工(树形依赖背包)

    题意 题目链接 Sol 树形依赖背包板子题 树形依赖背包大概就是说:对于一个点,只有选了它的父亲才能选自身 把dfs序建出来,倒过来考虑 设\(f[i][j]\)表示从第\(i\)个节点往后背包体积为 ...

  8. 【bzoj2427】【软件安装】tarjan缩点+树形依赖背包

    (上不了p站我要死了,侵权度娘背锅) Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上, ...

  9. 洛谷P1273 有线电视网 (树上分组背包)

    洛谷P1273 有线电视网 题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节 ...

随机推荐

  1. scidb

    貌似是给科学家用的数据库,暂不研究

  2. UIButton内部子控件自定义布局-“UIEdgeInsets”

    UIButton UIButton做frame动画时,不响应点击 在一个View内部加入几个按钮,然后改变这个view的frame来做动画,但是按钮不响应点击事件. 问题代码 __block CGRe ...

  3. c# 3D图形处理库

    C#的OpenGL类库SharpGL SharpGL 可以让你在 Windows Forms 或者 WPF 应用中轻松的使用 OpenGL 开发图形应用.更多SharpGL信息 Axiom 3D En ...

  4. 命令行编译 WPF

    在开发调试代码 WPF 时,经常需要在修改完成代码后,点击 Rebuild,然后到指定文件夹下点击打开对应的 .exe 验证程序是否正确, 可以通过以下命名实现修改程序后,点击一个 .bat 文件,直 ...

  5. 剑指offer-用两个栈实现队列05

    class Solution: def __init__(self): self.stackpush=[] self.stackpop=[] def push(self, node): # write ...

  6. 关于iframe的使用 以及自适应页面高度

    1. <a href="port" target="frame_view">港口资料</a> <iframe id="e ...

  7. PHP+IIS上传大文件

    最近刚接触IIS服务器,在使用php上传大文件的时候,遇到了一些问题.通过查阅网上资料进行了总结,希望对各位有帮助. 第一步,检查PHP的配置. 打开php.ini配置文件 1.file_upload ...

  8. io学习-相关文章

    文章:IO编程 地址:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143 ...

  9. javascript中将整数添加千位符号

    如果num是整数的话,将其转换成带千位符号的字符串: Number(num).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' +  ','); 另 ...

  10. systemtap如何写C函数 捎带着看看ret kprobe怎么用

    在systemstap中自定义函数 Embedded C can be the body of a script function. Instead enclosing the function bo ...