noip2006 金明的预算
题目链接:传送门
题目大意:略。。
题目思路:其实单就这道题来说,一个主件最多两个附件,且附件不再包含附件,所以很简单,但是如果主件的附件无限制,附件也可包含无限制的附件,应该怎么做?
首先推荐一篇论文 徐持衡的《浅谈几类背包题》,里面有详细的讲解,这一类树形依赖背包问题最终都能优化到 n*c 复杂度,n为物品数,c为背包容量
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <cctype>
#include <queue>
#include <string>
#include <vector>
#include<functional>
#include <set>
#include <map>
#include <climits>
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r
#define fi first
#define se second
#define ping(x,y) ((x-y)*(x-y))
#define mst(x,y) memset(x,y,sizeof(x))
#define mcp(x,y) memcpy(x,y,sizeof(y))
using namespace std;
#define gamma 0.5772156649015328606065120
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define N 1000005
#define maxn 32005
typedef pair<int,int> PII;
typedef long long LL; int n,m,x;
vector<int>V[];
int dp[][maxn];
int w[],v[];
void dfs(int u,int m){
if(m<=)return;
for(int e:V[u]){
for(int k=;k<=m;++k)dp[e][k]=dp[u][k];
dfs(e,m-w[e]);
for(int k=w[e];k<=m;++k)dp[u][k]=max(dp[u][k],dp[e][k-w[e]]+v[e]);
}
}
int main(){
int i,j,group,x,y;
while(scanf("%d%d",&m,&n)!=EOF){
mst(dp,);
for(i=;i<=n;++i)V[i].clear();
for(i=;i<=n;++i){
scanf("%d%d%d",&w[i],&v[i],&x);
v[i]*=w[i];
V[x].push_back(i);
}
dfs(,m);
printf("%d\n",dp[][m]);
}
return ;
}
然后再从这道题谈谈我对树形依赖背包的理解,不管怎么想怎么做,这是背包问题。
也就是对于一个物品,存在拿与不拿的情况,而如果不拿父节点,那么子节点也就只有不拿的情况。
加上树形结构以后,我们依然要保持背包的性质不变,也就是维护容量V包含价值最优的情况。
因为N*C^2复杂度有太多优秀的博客介绍,这里就不再赘述。
讲下个人对于 N*C 复杂度解法的理解。首先 二维数组 dp[u][V] ,u代表当前处理的节点u, V代表当前处理的容量(V<=背包总容量),整个 dp[u][V]保存的是处理到节点u容量V时的最优价值(处理到u,代表u节点左边所有的节点都已处理完毕)以及u所有子节点容量为V的最优值。
我们在处理节点时,存在拿与不拿的情况,而想选子节点则必须拿。那么假设处理到了节点x,我们可以先强制拿节点 x,这样就可以很方便的处理x的子节点,递归下去,对于子节点也同样处理,这样递归到底层时,我们把能拿的子节点都拿完了,但是这不一定是最优解,所以回溯的时候,则需要对拿与不拿进行取舍,因为是从子节点回溯,并且我们递归的时候是强制拿父节点的,因此可以直接选择 拿不拿子节点,而不用管父节点的限制,这样回溯维护最优值。
vector<int>V[];
int dp[][maxn];
int w[],v[];
void dfs(int u,int m){ ///u 父节点,m 当前可用容量(m<总容量)
if(m<=0)return; ///没有可用容量,背包装满了。。
for(int e:V[u]){ /// e 子节点
for(int k=;k<=m-w[e];++k)dp[e][k]=dp[u][k]; /// * 1 *
dfs(e,m-w[e]); ///强制拿e,方便处理e子节点 * 2 *
for(int k=w[e];k<=m;++k)dp[u][k]=max(dp[u][k],dp[e][k-w[e]]+v[e]);
///回溯更新 拿e后的最优值 与 不拿e ,保存两者最优值
}
}
在分析 * 1 *与 * 2 *;
* 1 *:和学长讨论了下是否有必要加上这个赋值循环?当然需要。对于节点e来说,强制拿e是在处理完e之前所有节点的基础上进行的,也就是在之前节点最优值的基础上进行的。
否则对于 e 来说,它与整个树的关系脱离,它最后得到的值与与父节点保存的值没有比较的意义。
* 2 *:m-w[e]就代表强制拿了e,因为背包中已经有部分体积被e 所占,e的价值只需回溯的时候加上进行更新即可。但是这里似乎没有体现出 强制拿 u?因为依赖背包题目一般给
的是一片森林。我们为了方便处理,可以加上一个虚拟树根,重量价值都为0,这样调用的时候,直接dfs(虚拟树根,背包总容量)。
不过感觉* 1 *处还是没有解释好,希望能有大牛补充,有不对的地方也请指出,,,
noip2006 金明的预算的更多相关文章
- [codevs1155][KOJ0558][COJ0178][NOIP2006]金明的预算方案
[codevs1155][KOJ0558][COJ0178][NOIP2006]金明的预算方案 试题描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴 ...
- Luogu 1064 金明的预算方案 / CJOJ 1352 [NOIP2006] 金明的预算方案(动态规划)
Luogu 1064 金明的预算方案 / CJOJ 1352 [NOIP2006] 金明的预算方案(动态规划) Description 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己 ...
- NOIP2006 金明的预算方案
1. 金明的预算方案 (budget.pas/c/cpp) [问题描述] 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈 ...
- [LuoguP1064][Noip2006]金明的预算方案
金明的预算方案(Link) 题目描述 现在有\(M\)个物品,每一个物品有一个钱数和重要度,并且有一个\(Q\),如果\(Q = 0\),那么该物件可以单独购买,当\(Q != 0\)时,表示若要购买 ...
- 【洛谷P1064】[NOIP2006] 金明的预算方案
金明的预算方案 显然是个背包问题 把每个主件和它对应的附件放在一组,枚举每一组,有以下几种选法: 1.都不选 2.只选主件 3.一个主件+一个附件 4.一个主件+两个附件 于是就成了01背包.. #i ...
- NOIP2006金明的预算方案[DP 有依赖的背包问题]
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...
- NOIP 2006 金明的预算方案
洛谷 P1064 金明的预算方案 https://www.luogu.org/problem/P1064 JDOJ 1420: [NOIP2006]金明的预算方案 T2 https://neooj.c ...
- 「NOIP2006」「LuoguP1064」 金明的预算方案(分组背包
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NNN元钱就行” ...
- tyvj 1057 金明的预算方案 背包dp
P1057 金明的预算方案 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 NOIP2006 提高组 第二道 描述 金明今天很开心,家里购置的新房就要领钥匙了 ...
随机推荐
- 使用Guava报错NoSuchMethodError的解决方法
在使用Guava缓存的时候.系统报错: java.lang.NoSuchMethodError: com.google.common.base.Objects.firstNonNull 错误原因就是找 ...
- 【php】在php代码嵌入HTML代码(适用于公众号开发)
核心:HTML的双引号["]一定要转义,不废话: $link = "<a href=\"http://www.baidu.com\">最新活动链接& ...
- 【转】C# 视频监控系列(12):H264播放器——播放录像文件
原文地址:http://www.cnblogs.com/over140/archive/2009/03/23/1419643.html?spm=5176.100239.blogcont51182.16 ...
- ubuntu下创建.net core时出现 Failed to create prime the NuGet cache
https://docs.microsoft.com/en-us/aspnet/core/getting-started 根据微软给出的文档运行第一个web程序出现错误 Failed to creat ...
- Laravel 5 教程 - 文件上传
一.简介 Laravel 有很棒的文件系统抽象层,是基于 Frank de Jonge 的 Flysystem 扩展包. Laravel 集成的 Flysystem 提供了简单的接口,可以操作本地端空 ...
- EF(EntityFramework) Migrations 迁移
1.开启程序包管理器控制台 2.安装EntityFramework PM> Install-Package EntityFramework 3.启用迁移 PM> Enable-Migr ...
- Pedometer_forAndroid
https://github.com/Nicky213Zhang/Pedometer_forAndroid 自行封装了一个计步器控件,采用:计步传感器Sensor.TYPE_STEP_COUNTER计 ...
- [NM 状态机1] Application状态机详解
概述 前面已经分析了RM的状态机,接下来将分析NM的状态机,NM状态机包括Container,Application,LocalizedResource三个.首先我们分析Application的状态机 ...
- SPI—读写串行 FLASH
SPI协议简介SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线.它被广泛地使用在 ADC. LCD ...
- Jquery学习笔记(11)--jquery的ajax删除用户,非常简单!
jquery的ajax,简直简单!!只要一个$.get(url,map,function)就搞定了! index.php: <!DOCTYPE html> <html lang=&q ...